origen_llm 0.1.1
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 +7 -0
- data/app/lib/origen_llm/application.rb +54 -0
- data/app/lib/origen_llm/base.rb +55 -0
- data/app/lib/origen_llm/error_assistant/client.rb +167 -0
- data/app/lib/origen_llm/error_assistant/prompt.rb +30 -0
- data/app/lib/origen_llm/error_assistant.rb +34 -0
- data/app/lib/origen_llm/plugin.rb +64 -0
- data/app/lib/origen_llm.rb +28 -0
- data/app/templates/web/index.md.erb +37 -0
- data/app/templates/web/layouts/_basic.html.erb +13 -0
- data/app/templates/web/partials/_navbar.html.erb +20 -0
- data/app/templates/web/release_notes.md.erb +5 -0
- data/config/application.rb +97 -0
- data/config/boot.rb +24 -0
- data/config/commands.rb +79 -0
- data/config/load_generators.rb +6 -0
- data/config/version.rb +7 -0
- metadata +87 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 35096d0f51243b07497976cb516741e60a6f5d6c0962031a5d27b4aa72a6ca73
|
|
4
|
+
data.tar.gz: b478b14307e878e55585c931665a36177f63a6dae7c5489e81d21780337006dd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b8073db1863e0a3e6569eabe104e50beb6b1196c7eaaf68f5088d241109baa16ac31911b5ab70afe0b374cb7172ea198a3367183d23d097e8d792db0ee465c7e
|
|
7
|
+
data.tar.gz: 775b46a092a41be4361ca4fa7239adc1c67b69c217dc23c0112d6af0058d97d4da56deacf2c73a46f056ab5abe6e318ed37213d7175c4a67297419d25117309e
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module OrigenLlm
|
|
2
|
+
# This will be the parent class of all of your application generators, it provides a place
|
|
3
|
+
# to add anything that you want to be added to all of your applications
|
|
4
|
+
class Application < OrigenAppGenerators::Application
|
|
5
|
+
include Base
|
|
6
|
+
|
|
7
|
+
# Any methods added above the protected line will get automatically invoked
|
|
8
|
+
# at the start of *all* of your application generators.
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
# You can add helper methods that you want to make available to all of your application
|
|
13
|
+
# generators here, these will not get called unless a child generator calls them.
|
|
14
|
+
|
|
15
|
+
# Here you can modify the default list of files that are included in all of your applications.
|
|
16
|
+
#
|
|
17
|
+
# See here for the default list of files:
|
|
18
|
+
# https://github.com/Origen-SDK/origen_app_generators/blob/master/lib/origen_app_generators/application.rb
|
|
19
|
+
#
|
|
20
|
+
# The filelist can contain references to generate files, directories or symlinks in the
|
|
21
|
+
# new application.
|
|
22
|
+
#
|
|
23
|
+
# To make your generators more maintainable, try and re-use as much as possible
|
|
24
|
+
# from the parent generator, this means that your generator will automatically stay up
|
|
25
|
+
# to date with the latest conventions.
|
|
26
|
+
#
|
|
27
|
+
# Additional files can be added or removed from the filelist as shown below.
|
|
28
|
+
def filelist
|
|
29
|
+
@filelist ||= begin
|
|
30
|
+
list = super # Always pick up the parent list
|
|
31
|
+
# Example of how to remove a file from the parent list
|
|
32
|
+
# list.delete(:web_doc_layout)
|
|
33
|
+
# Example of how to add a file, in this case the file will be compiled and copied to
|
|
34
|
+
# the same location in the new app
|
|
35
|
+
# list[:config_shared_commands] = { source: 'config/shared_commands.rb' }
|
|
36
|
+
# Alternatively specifying a different destination, typically you would do this when
|
|
37
|
+
# the final location is dynamic
|
|
38
|
+
# list[:gemspec] = { source: 'gemspec.rb', dest: "#{@name}.gemspec" }
|
|
39
|
+
# Example of how to recursively copy a directory
|
|
40
|
+
# list[:copy_dir] = { source: 'src_dir', dest: 'dest_dir', type: :directory, copy: true }
|
|
41
|
+
# Example of how to create a directory
|
|
42
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory }
|
|
43
|
+
# By default, directories created in this way will contain a .keep file, to inhibit this:
|
|
44
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory, nokeep: true }
|
|
45
|
+
# Example of how to create a symlink
|
|
46
|
+
# list[:target_default] = { source: 'debug.rb', # Relative to the file being linked to
|
|
47
|
+
# dest: 'target/default.rb', # Relative to destination_root
|
|
48
|
+
# type: :symlink }
|
|
49
|
+
# Remember to return the final list
|
|
50
|
+
list
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module OrigenLlm
|
|
2
|
+
# This is a mixin that is included in both the application and plugin
|
|
3
|
+
# generators, it provides a place to add things that should apply to
|
|
4
|
+
# all of your applications and plugins
|
|
5
|
+
module Base
|
|
6
|
+
# Any helper methods added to this base module will not be automatically invoked,
|
|
7
|
+
# you must call them from either the top-level application or plugin generators,
|
|
8
|
+
# or from a child generator.
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
# Here you can modify the default list of files that are included in all of your
|
|
13
|
+
# applications AND plugins.
|
|
14
|
+
#
|
|
15
|
+
# See here for the default list of files:
|
|
16
|
+
# https://github.com/Origen-SDK/origen_app_generators/blob/master/lib/origen_app_generators/application.rb
|
|
17
|
+
# If the child generator is a plugin, then this list is then modified by the base plugin generator which
|
|
18
|
+
# you can see here:
|
|
19
|
+
# https://github.com/Origen-SDK/origen_app_generators/blob/master/lib/origen_app_generators/plugin.rb
|
|
20
|
+
#
|
|
21
|
+
# The filelist can contain references to generate files, directories or symlinks in the
|
|
22
|
+
# new application.
|
|
23
|
+
#
|
|
24
|
+
# To make your generators more maintainable, try and re-use as much as possible
|
|
25
|
+
# from the parent generators, this means that your generator will automatically stay up
|
|
26
|
+
# to date with the latest conventions.
|
|
27
|
+
#
|
|
28
|
+
# Additional files can be added or removed from the filelist as shown below.
|
|
29
|
+
def filelist
|
|
30
|
+
@filelist ||= begin
|
|
31
|
+
list = super # Always pick up the parent list
|
|
32
|
+
# Example of how to remove a file from the parent list
|
|
33
|
+
# list.delete(:web_doc_layout)
|
|
34
|
+
# Example of how to add a file, in this case the file will be compiled and copied to
|
|
35
|
+
# the same location in the new app
|
|
36
|
+
# list[:config_shared_commands] = { source: 'config/shared_commands.rb' }
|
|
37
|
+
# Alternatively specifying a different destination, typically you would do this when
|
|
38
|
+
# the final location is dynamic
|
|
39
|
+
# list[:gemspec] = { source: 'gemspec.rb', dest: "#{@name}.gemspec" }
|
|
40
|
+
# Example of how to recursively copy a directory
|
|
41
|
+
# list[:copy_dir] = { source: 'src_dir', dest: 'dest_dir', type: :directory, copy: true }
|
|
42
|
+
# Example of how to create a directory
|
|
43
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory }
|
|
44
|
+
# By default, directories created in this way will contain a .keep file, to inhibit this:
|
|
45
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory, nokeep: true }
|
|
46
|
+
# Example of how to create a symlink
|
|
47
|
+
# list[:target_default] = { source: 'debug.rb', # Relative to the file being linked to
|
|
48
|
+
# dest: 'target/default.rb', # Relative to destination_root
|
|
49
|
+
# type: :symlink }
|
|
50
|
+
# Remember to return the final list
|
|
51
|
+
list
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'uri'
|
|
4
|
+
|
|
5
|
+
module OrigenLlm
|
|
6
|
+
class ErrorAssistantClient
|
|
7
|
+
DEFAULT_AUTH_MODE = 'x_api_key'
|
|
8
|
+
DEFAULT_PROVIDER_MODE = 'generic'
|
|
9
|
+
DEFAULT_MAX_TOKENS = 200
|
|
10
|
+
DEFAULT_TEMPERATURE = 0.2
|
|
11
|
+
DEFAULT_TIMEOUT = 3.0
|
|
12
|
+
|
|
13
|
+
def initialize(context:)
|
|
14
|
+
@api_url = context[:api_url]
|
|
15
|
+
@provider_mode = (context[:provider_mode] || DEFAULT_PROVIDER_MODE).to_s
|
|
16
|
+
@model = context[:model]
|
|
17
|
+
@max_tokens = coerce_integer(context[:max_tokens], DEFAULT_MAX_TOKENS)
|
|
18
|
+
@temperature = coerce_float(context[:temperature], DEFAULT_TEMPERATURE)
|
|
19
|
+
@api_key_env = context[:api_key_env]
|
|
20
|
+
@auth_mode = (context[:auth_mode] || DEFAULT_AUTH_MODE).to_s
|
|
21
|
+
@auth_header_name = context[:auth_header_name]
|
|
22
|
+
@auth_prefix = context[:auth_prefix]
|
|
23
|
+
@extra_headers = context[:extra_headers].is_a?(Hash) ? context[:extra_headers] : {}
|
|
24
|
+
@prompt_mode = (context[:prompt_mode] || 'default').to_s
|
|
25
|
+
@backend_profile = context[:backend_profile]
|
|
26
|
+
@backend_context = context[:backend_context].is_a?(Hash) ? context[:backend_context] : {}
|
|
27
|
+
@timeout = coerce_float(context[:timeout_seconds], DEFAULT_TIMEOUT)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def analyze(prompt:, exception_message:, app_stack:)
|
|
31
|
+
return nil if @api_url.to_s.strip.empty?
|
|
32
|
+
return nil if anthropic_mode? && @model.to_s.strip.empty?
|
|
33
|
+
|
|
34
|
+
uri = request_uri
|
|
35
|
+
req = Net::HTTP::Post.new(uri)
|
|
36
|
+
req['Content-Type'] = 'application/json'
|
|
37
|
+
build_headers.each { |k, v| req[k] = v }
|
|
38
|
+
req.body = JSON.dump(build_request_payload(
|
|
39
|
+
prompt: prompt,
|
|
40
|
+
exception_message: exception_message,
|
|
41
|
+
app_stack: app_stack
|
|
42
|
+
))
|
|
43
|
+
|
|
44
|
+
res = Net::HTTP.start(
|
|
45
|
+
uri.host,
|
|
46
|
+
uri.port,
|
|
47
|
+
use_ssl: uri.scheme == 'https',
|
|
48
|
+
open_timeout: @timeout,
|
|
49
|
+
read_timeout: @timeout
|
|
50
|
+
) do |http|
|
|
51
|
+
http.request(req)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
return nil unless res.is_a?(Net::HTTPSuccess)
|
|
55
|
+
|
|
56
|
+
parsed = begin
|
|
57
|
+
JSON.parse(res.body)
|
|
58
|
+
rescue
|
|
59
|
+
{}
|
|
60
|
+
end
|
|
61
|
+
extract_answer(parsed)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def secret
|
|
67
|
+
return nil if @api_key_env.to_s.strip.empty?
|
|
68
|
+
|
|
69
|
+
ENV[@api_key_env]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def build_headers
|
|
73
|
+
headers = {}
|
|
74
|
+
key = secret
|
|
75
|
+
|
|
76
|
+
case @auth_mode
|
|
77
|
+
when 'none'
|
|
78
|
+
# No auth header
|
|
79
|
+
when 'x_api_key'
|
|
80
|
+
header_name = @auth_header_name.to_s.strip.empty? ? 'X-API-Key' : @auth_header_name
|
|
81
|
+
headers[header_name] = key if key && !key.empty?
|
|
82
|
+
when 'bearer'
|
|
83
|
+
header_name = @auth_header_name.to_s.strip.empty? ? 'Authorization' : @auth_header_name
|
|
84
|
+
prefix = @auth_prefix.nil? ? 'Bearer ' : @auth_prefix
|
|
85
|
+
headers[header_name] = "#{prefix}#{key}" if key && !key.empty?
|
|
86
|
+
when 'ocp_apim_subscription_key'
|
|
87
|
+
header_name = @auth_header_name.to_s.strip.empty? ? 'Ocp-Apim-Subscription-Key' : @auth_header_name
|
|
88
|
+
headers[header_name] = key if key && !key.empty?
|
|
89
|
+
else
|
|
90
|
+
header_name = @auth_header_name.to_s.strip.empty? ? 'X-API-Key' : @auth_header_name
|
|
91
|
+
headers[header_name] = key if key && !key.empty?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
@extra_headers.each do |k, v|
|
|
95
|
+
headers[k.to_s] = v.to_s
|
|
96
|
+
end
|
|
97
|
+
headers
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_request_payload(prompt:, exception_message:, app_stack:)
|
|
101
|
+
if anthropic_mode?
|
|
102
|
+
{
|
|
103
|
+
model: @model,
|
|
104
|
+
max_tokens: @max_tokens,
|
|
105
|
+
temperature: @temperature,
|
|
106
|
+
messages: [{ role: 'user', content: prompt }]
|
|
107
|
+
}
|
|
108
|
+
else
|
|
109
|
+
payload = {
|
|
110
|
+
question: prompt,
|
|
111
|
+
context: {
|
|
112
|
+
exception_message: exception_message,
|
|
113
|
+
application_stack: Array(app_stack)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
payload[:model] = @model unless @model.to_s.strip.empty?
|
|
117
|
+
|
|
118
|
+
if @prompt_mode == 'backend_profile' && !@backend_profile.to_s.strip.empty?
|
|
119
|
+
payload[:profile_id] = @backend_profile
|
|
120
|
+
payload[:backend_context] = @backend_context unless @backend_context.empty?
|
|
121
|
+
end
|
|
122
|
+
payload
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def request_uri
|
|
127
|
+
uri = URI.parse(@api_url)
|
|
128
|
+
return uri unless anthropic_mode?
|
|
129
|
+
|
|
130
|
+
if uri.path.to_s.empty? || uri.path == '/'
|
|
131
|
+
uri.path = '/v1/messages'
|
|
132
|
+
elsif !uri.path.end_with?('/v1/messages')
|
|
133
|
+
uri.path = "#{uri.path.sub(%r{/$}, '')}/v1/messages"
|
|
134
|
+
end
|
|
135
|
+
uri
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def extract_answer(parsed)
|
|
139
|
+
if anthropic_mode?
|
|
140
|
+
content = parsed['content']
|
|
141
|
+
if content.is_a?(Array)
|
|
142
|
+
text_parts = content.select { |c| c.is_a?(Hash) && c['type'] == 'text' }.map { |c| c['text'].to_s }
|
|
143
|
+
answer = text_parts.join("\n").strip
|
|
144
|
+
return answer unless answer.empty?
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
parsed['answer'] || parsed['suggestion'] || parsed['output'] || parsed['text']
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def anthropic_mode?
|
|
152
|
+
@provider_mode == 'anthropic_messages'
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def coerce_integer(value, default_value)
|
|
156
|
+
Integer(value)
|
|
157
|
+
rescue
|
|
158
|
+
default_value
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def coerce_float(value, default_value)
|
|
162
|
+
Float(value)
|
|
163
|
+
rescue
|
|
164
|
+
default_value
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module OrigenLlm
|
|
4
|
+
# Module for building prompts for error analysis
|
|
5
|
+
module ErrorAssistantPrompt
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def build(exception_message:, app_stack:, mode: nil, site_template: nil)
|
|
9
|
+
if mode.to_s == 'site_template' && !site_template.to_s.strip.empty?
|
|
10
|
+
return site_template
|
|
11
|
+
.gsub('%<exception_message>s', exception_message.to_s)
|
|
12
|
+
.gsub('%<application_stack>s', Array(app_stack).join("\n"))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
<<~PROMPT
|
|
16
|
+
You are diagnosing an Origen application runtime failure.
|
|
17
|
+
Return:
|
|
18
|
+
1) Most likely root cause (1-2 sentences)
|
|
19
|
+
2) Suggested fix steps (max 5 bullets)
|
|
20
|
+
3) Confidence (low/medium/high)
|
|
21
|
+
|
|
22
|
+
Exception:
|
|
23
|
+
#{exception_message}
|
|
24
|
+
|
|
25
|
+
Application stack:
|
|
26
|
+
#{Array(app_stack).join("\n")}
|
|
27
|
+
PROMPT
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require_relative 'error_assistant/client'
|
|
2
|
+
require_relative 'error_assistant/prompt'
|
|
3
|
+
|
|
4
|
+
module OrigenLlm
|
|
5
|
+
module ErrorAssistant
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def analyze(exception_message:, app_stack:, context: {})
|
|
9
|
+
prompt = OrigenLlm::ErrorAssistantPrompt.build(
|
|
10
|
+
exception_message: exception_message,
|
|
11
|
+
app_stack: app_stack,
|
|
12
|
+
mode: context[:prompt_mode],
|
|
13
|
+
site_template: context[:prompt_template]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
response = OrigenLlm::ErrorAssistantClient.new(context: context).analyze(
|
|
17
|
+
prompt: prompt,
|
|
18
|
+
exception_message: exception_message,
|
|
19
|
+
app_stack: app_stack
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
normalize_response(response)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def normalize_response(response)
|
|
26
|
+
return nil if response.nil?
|
|
27
|
+
|
|
28
|
+
text = response.to_s.strip
|
|
29
|
+
return nil if text.empty?
|
|
30
|
+
|
|
31
|
+
text
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module OrigenLlm
|
|
2
|
+
# This will be the parent class of all of your plugin generators, it provides a place
|
|
3
|
+
# to add anything that you want to be added to all of your plugins
|
|
4
|
+
class Plugin < OrigenAppGenerators::Plugin
|
|
5
|
+
include Base
|
|
6
|
+
|
|
7
|
+
def initialize(*args)
|
|
8
|
+
# This makes all of your plugins be configured for internal distribution, i.e. rather
|
|
9
|
+
# than via rubygems.org
|
|
10
|
+
@audience = :internal
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Any methods added above the protected line will get automatically invoked
|
|
15
|
+
# at the start of *all* of your plugin generators.
|
|
16
|
+
|
|
17
|
+
protected
|
|
18
|
+
|
|
19
|
+
# You can add helper methods that you want to make available to all of your plugin
|
|
20
|
+
# generators here, these will not get called unless a child generator calls them.
|
|
21
|
+
|
|
22
|
+
# Here you can modify the default list of files that are included in all of your plugins.
|
|
23
|
+
#
|
|
24
|
+
# Since this is a plugin generator, the default list of files comprises the application list,
|
|
25
|
+
# which you can see here:
|
|
26
|
+
# https://github.com/Origen-SDK/origen_app_generators/blob/master/lib/origen_app_generators/application.rb
|
|
27
|
+
# And this is then modified by the base plugin generator which you can see here:
|
|
28
|
+
# https://github.com/Origen-SDK/origen_app_generators/blob/master/lib/origen_app_generators/plugin.rb
|
|
29
|
+
#
|
|
30
|
+
# The filelist can contain references to generate files, directories or symlinks in the
|
|
31
|
+
# new plugin.
|
|
32
|
+
#
|
|
33
|
+
# To make your generators more maintainable, try and re-use as much as possible
|
|
34
|
+
# from the parent generator, this means that your generators will automatically stay up
|
|
35
|
+
# to date with the latest conventions.
|
|
36
|
+
#
|
|
37
|
+
# Additional files can be added or removed from the filelist as shown below.
|
|
38
|
+
def filelist
|
|
39
|
+
@filelist ||= begin
|
|
40
|
+
list = super # Always pick up the parent list
|
|
41
|
+
# Example of how to remove a file from the parent list
|
|
42
|
+
# list.delete(:web_doc_layout)
|
|
43
|
+
# Example of how to add a file, in this case the file will be compiled and copied to
|
|
44
|
+
# the same location in the new app
|
|
45
|
+
# list[:config_shared_commands] = { source: 'config/shared_commands.rb' }
|
|
46
|
+
# Alternatively specifying a different destination, typically you would do this when
|
|
47
|
+
# the final location is dynamic
|
|
48
|
+
# list[:gemspec] = { source: 'gemspec.rb', dest: "#{@name}.gemspec" }
|
|
49
|
+
# Example of how to recursively copy a directory
|
|
50
|
+
# list[:copy_dir] = { source: 'src_dir', dest: 'dest_dir', type: :directory, copy: true }
|
|
51
|
+
# Example of how to create a directory
|
|
52
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory }
|
|
53
|
+
# By default, directories created in this way will contain a .keep file, to inhibit this:
|
|
54
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory, nokeep: true }
|
|
55
|
+
# Example of how to create a symlink
|
|
56
|
+
# list[:target_default] = { source: 'debug.rb', # Relative to the file being linked to
|
|
57
|
+
# dest: 'target/default.rb', # Relative to destination_root
|
|
58
|
+
# type: :symlink }
|
|
59
|
+
# Remember to return the final list
|
|
60
|
+
list
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'origen_app_generators'
|
|
2
|
+
require 'origen_llm/base'
|
|
3
|
+
require 'origen_llm/application'
|
|
4
|
+
require 'origen_llm/plugin'
|
|
5
|
+
require 'origen_llm/error_assistant'
|
|
6
|
+
|
|
7
|
+
module OrigenLlm
|
|
8
|
+
# Define test sets of inputs to test your generators. The last item in each array is
|
|
9
|
+
# required and always indicates what action should be taken once the application has
|
|
10
|
+
# been built. nil means take no action, :default means to run a default set of test
|
|
11
|
+
# operations, and an array of Origen command strings gives you control of exactly
|
|
12
|
+
# what to run.
|
|
13
|
+
#
|
|
14
|
+
# These inputs can be executed individually by running 'origen app_gen:test -i INDEX',
|
|
15
|
+
# where INDEX is the index number of the set you want to execute from the TEST_INPUTS
|
|
16
|
+
# array.
|
|
17
|
+
#
|
|
18
|
+
# You can also execute all sets of test inputs by running: 'origen app_gen:test -r'
|
|
19
|
+
TEST_INPUTS = [] # END_OF_TEST_INPUTS Don't remove this comment, it is used by the app_gen:new command!
|
|
20
|
+
|
|
21
|
+
# As you add new generators to this app they will be entered here, this enables the
|
|
22
|
+
# mechanism to register them with the 'origen new' command.
|
|
23
|
+
# You should generally not modify this by hand, instead use the 'origen app_gen:new'
|
|
24
|
+
# command every time you want to create a new generator, and this will be filled in
|
|
25
|
+
# for you.
|
|
26
|
+
AVAILABLE = {
|
|
27
|
+
}
|
|
28
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
% render "layouts/basic.html" do
|
|
2
|
+
|
|
3
|
+
%# HTML tags can be embedded in mark down files if you want to do specific custom
|
|
4
|
+
%# formatting like this, but in most cases that is not required.
|
|
5
|
+
<h1><%= Origen.app.namespace %> <span style="font-size: 14px">(<%= Origen.app.version %>)</span></h1>
|
|
6
|
+
|
|
7
|
+
### Purpose
|
|
8
|
+
|
|
9
|
+
This plugin...
|
|
10
|
+
|
|
11
|
+
### How To Install
|
|
12
|
+
|
|
13
|
+
In your Gemfile add:
|
|
14
|
+
|
|
15
|
+
~~~ruby
|
|
16
|
+
gem "<%= Origen.app.name %>"
|
|
17
|
+
~~~
|
|
18
|
+
|
|
19
|
+
or if your application is a plugin, then add this to your <code>.gemspec</code>
|
|
20
|
+
|
|
21
|
+
~~~ruby
|
|
22
|
+
spec.add_runtime_dependency "<%= Origen.app.name %>", ">= <%= Origen.app.version %>"
|
|
23
|
+
~~~
|
|
24
|
+
|
|
25
|
+
__NOTE:__ In the case of a plugin, you will also need to <code>require '<%= Origen.app.name %>'</code> somewhere in your environment.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### How To Use
|
|
29
|
+
|
|
30
|
+
Add quickstart documentation here...
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### How To Setup a Development Environment
|
|
34
|
+
|
|
35
|
+
Describe how a developer would setup a new workspace for this plugin...
|
|
36
|
+
|
|
37
|
+
% end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: <%= options[:title] || Origen.config.name %>
|
|
3
|
+
---
|
|
4
|
+
<%= render "partials/navbar.html", tab: options[:tab] %>
|
|
5
|
+
|
|
6
|
+
<div class="row">
|
|
7
|
+
%# The markdown attribute is important if you are going to include content written
|
|
8
|
+
%# in markdown, without this is will be included verbatim
|
|
9
|
+
<div class="span12" markdown="1">
|
|
10
|
+
<%= yield %>
|
|
11
|
+
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<nav class="navbar navbar-inverse navbar-fixed-top">
|
|
2
|
+
<div class="container">
|
|
3
|
+
<div class="navbar-header">
|
|
4
|
+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
|
5
|
+
<span class="sr-only">Toggle navigation</span>
|
|
6
|
+
<span class="icon-bar"></span>
|
|
7
|
+
<span class="icon-bar"></span>
|
|
8
|
+
<span class="icon-bar"></span>
|
|
9
|
+
</button>
|
|
10
|
+
<a class="navbar-brand" href="<%= path "/" %>">Home</a>
|
|
11
|
+
</div>
|
|
12
|
+
<div id="navbar" class="collapse navbar-collapse">
|
|
13
|
+
<ul class="nav navbar-nav">
|
|
14
|
+
<li class="<%= options[:tab] == :api ? 'active' : '' %>"><a href="<%= path "/api/" %>">API</a></li>
|
|
15
|
+
<li class="<%= options[:tab] == :release ? 'active' : '' %>"><a href="<%= path "/release_notes" %>">Release Notes</a></li>
|
|
16
|
+
</ul>
|
|
17
|
+
<%= import "origen/web/logo.html" %>
|
|
18
|
+
</div><!--/.nav-collapse -->
|
|
19
|
+
</div>
|
|
20
|
+
</nav>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'origen'
|
|
2
|
+
class OrigenLlmApplication < Origen::Application
|
|
3
|
+
# See http://origen-sdk.org/origen/api/Origen/Application/Configuration.html
|
|
4
|
+
# for a full list of the configuration options available
|
|
5
|
+
|
|
6
|
+
# These attributes should never be changed, the duplication here will be resolved in future
|
|
7
|
+
# by condensing these attributes that do similar things
|
|
8
|
+
self.name = 'origen_llm'
|
|
9
|
+
self.namespace = 'OrigenLlm'
|
|
10
|
+
config.name = 'origen_llm'
|
|
11
|
+
config.initials = 'OrigenLlm'
|
|
12
|
+
# Change this to point to the revision control repository for this plugin
|
|
13
|
+
config.rc_url = 'git@github.com:Origen-SDK/origen_llm.git'
|
|
14
|
+
|
|
15
|
+
# To enable deployment of your documentation to a web server (via the 'origen web'
|
|
16
|
+
# command) fill in these attributes.
|
|
17
|
+
# config.web_directory = '/path/to/server/origen_llm'
|
|
18
|
+
# config.web_domain = 'http://origen.mycompany.net/origen_llm'
|
|
19
|
+
|
|
20
|
+
# When false Origen will be less strict about checking for some common coding errors,
|
|
21
|
+
# it is recommended that you leave this to true for better feedback and easier debug.
|
|
22
|
+
# This will be the default setting in Origen v3.
|
|
23
|
+
config.strict_errors = true
|
|
24
|
+
|
|
25
|
+
# See: http://origen-sdk.org/origen/latest/guides/utilities/lint/
|
|
26
|
+
config.lint_test = {
|
|
27
|
+
# Require the lint tests to pass before allowing a release to proceed
|
|
28
|
+
run_on_tag: true,
|
|
29
|
+
# Auto correct violations where possible whenever 'origen lint' is run
|
|
30
|
+
auto_correct: true,
|
|
31
|
+
# Run on these directories/files by default
|
|
32
|
+
files: ['app', 'config/application.rb']
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
config.semantically_version = true
|
|
36
|
+
|
|
37
|
+
# An example of how to set application specific LSF parameters
|
|
38
|
+
# config.lsf.project = "msg.te"
|
|
39
|
+
|
|
40
|
+
# An example of how to specify a prefix to add to all generated patterns
|
|
41
|
+
# config.pattern_prefix = "nvm"
|
|
42
|
+
|
|
43
|
+
# An example of how to add header comments to all generated patterns
|
|
44
|
+
# config.pattern_header do
|
|
45
|
+
# cc "This is a pattern created by the example origen application"
|
|
46
|
+
# end
|
|
47
|
+
|
|
48
|
+
# By default all generated output will end up in ./output.
|
|
49
|
+
# Here you can specify an alternative directory entirely, or make it dynamic such that
|
|
50
|
+
# the output ends up in a setup specific directory.
|
|
51
|
+
# config.output_directory do
|
|
52
|
+
# "#{Origen.root}/output/#{$dut.class}"
|
|
53
|
+
# end
|
|
54
|
+
|
|
55
|
+
# Similarly for the reference files, generally you want to setup the reference directory
|
|
56
|
+
# structure to mirror that of your output directory structure.
|
|
57
|
+
# config.reference_directory do
|
|
58
|
+
# "#{Origen.root}/.ref/#{$dut.class}"
|
|
59
|
+
# end
|
|
60
|
+
|
|
61
|
+
# This will automatically deploy your documentation after every tag
|
|
62
|
+
# def after_release_email(tag, note, type, selector, options)
|
|
63
|
+
# command = "origen web compile --remote --api"
|
|
64
|
+
# Dir.chdir Origen.root do
|
|
65
|
+
# system command
|
|
66
|
+
# end
|
|
67
|
+
# end
|
|
68
|
+
# Ensure that all tests pass before allowing a release to continue
|
|
69
|
+
def validate_release
|
|
70
|
+
if !system('origen app_gen:test --regression')
|
|
71
|
+
puts "Sorry but you can't release with failing tests, please fix them and try again."
|
|
72
|
+
exit 1
|
|
73
|
+
else
|
|
74
|
+
puts 'All tests passing, proceeding with release process!'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# To enabled source-less pattern generation create a class (for example PatternDispatcher)
|
|
79
|
+
# to generate the pattern. This should return false if the requested pattern has been
|
|
80
|
+
# dispatched, otherwise Origen will proceed with looking up a pattern source as normal.
|
|
81
|
+
# def before_pattern_lookup(requested_pattern)
|
|
82
|
+
# PatternDispatcher.new.dispatch_or_return(requested_pattern)
|
|
83
|
+
# end
|
|
84
|
+
|
|
85
|
+
# If you use pattern iterators you may come across the case where you request a pattern
|
|
86
|
+
# like this:
|
|
87
|
+
# origen g example_pat_b0.atp
|
|
88
|
+
#
|
|
89
|
+
# However it cannot be found by Origen since the pattern name is actually example_pat_bx.atp
|
|
90
|
+
# In the case where the pattern cannot be found Origen will pass the name to this translator
|
|
91
|
+
# if it exists, and here you can make any substitutions to help Origen find the file you
|
|
92
|
+
# want. In this example any instances of _b\d, where \d means a number, are replaced by
|
|
93
|
+
# _bx.
|
|
94
|
+
# config.pattern_name_translator do |name|
|
|
95
|
+
# name.gsub(/_b\d/, "_bx")
|
|
96
|
+
# end
|
|
97
|
+
end
|
data/config/boot.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# This file is used to boot your plugin when it is running in standalone mode
|
|
2
|
+
# from its own workspace - i.e. when the plugin is being developed.
|
|
3
|
+
#
|
|
4
|
+
# It will not be loaded when the plugin is imported by a 3rd party app - in that
|
|
5
|
+
# case only lib/origen_llm.rb is loaded.
|
|
6
|
+
#
|
|
7
|
+
# Therefore this file can be used to load anything extra that you need to boot
|
|
8
|
+
# the development environment for this app. For example, this is typically used
|
|
9
|
+
# to load some additional test classes to use your plugin APIs so that they can
|
|
10
|
+
# be tested and/or interacted with in the console.
|
|
11
|
+
require "origen_llm"
|
|
12
|
+
|
|
13
|
+
module OrigenLlmDev
|
|
14
|
+
# Example of how to explicitly require a file
|
|
15
|
+
# require "origen_llm_dev/my_file"
|
|
16
|
+
|
|
17
|
+
# Load all files in the lib/origen_llm_dev directory.
|
|
18
|
+
# Note that there is no problem from requiring a file twice (Ruby will ignore
|
|
19
|
+
# the second require), so if you have a file that must be required first, then
|
|
20
|
+
# explicitly require it up above and then let this take care of the rest.
|
|
21
|
+
Dir.glob("#{File.dirname(__FILE__)}/../lib/origen_llm_dev/**/*.rb").sort.each do |file|
|
|
22
|
+
require file
|
|
23
|
+
end
|
|
24
|
+
end
|
data/config/commands.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# This file should be used to extend the origen with application specific commands
|
|
2
|
+
|
|
3
|
+
# Map any command aliases here, for example to allow 'origen ex' to refer to a
|
|
4
|
+
# command called execute you would add a reference as shown below:
|
|
5
|
+
aliases ={
|
|
6
|
+
# "ex" => "execute",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# The requested command is passed in here as @command, this checks it against
|
|
10
|
+
# the above alias table and should not be removed.
|
|
11
|
+
@command = aliases[@command] || @command
|
|
12
|
+
|
|
13
|
+
# Now branch to the specific task code
|
|
14
|
+
case @command
|
|
15
|
+
|
|
16
|
+
# (Working) example of how to create an application specific comment, here to generate
|
|
17
|
+
# a tags file for you application to enable method definition lookup and similar within
|
|
18
|
+
# editors/IDEs
|
|
19
|
+
when "tags"
|
|
20
|
+
# Here the logic is just written in-line, alternatively it could be written in a
|
|
21
|
+
# dedicated file and required here, e.g.
|
|
22
|
+
#require "origen_llm/commands/my_command" # Would load file lib/origen_llm/commands/my_command.rb
|
|
23
|
+
Dir.chdir Origen.root do
|
|
24
|
+
system("ripper-tags -R")
|
|
25
|
+
end
|
|
26
|
+
# You must always exit upon successfully capturing and executing a command to prevent
|
|
27
|
+
# control flowing back to Origen
|
|
28
|
+
exit 0
|
|
29
|
+
|
|
30
|
+
## Example of how to make a command to run unit tests, this simply invokes RSpec on
|
|
31
|
+
## the spec directory
|
|
32
|
+
#when "specs"
|
|
33
|
+
# require "rspec"
|
|
34
|
+
# exit RSpec::Core::Runner.run(['spec'])
|
|
35
|
+
|
|
36
|
+
## Example of how to make a command to run diff-based tests
|
|
37
|
+
#when "examples", "test"
|
|
38
|
+
# Origen.load_application
|
|
39
|
+
# status = 0
|
|
40
|
+
#
|
|
41
|
+
# # Compiler tests
|
|
42
|
+
# ARGV = %w(templates/example.txt.erb -t debug -r approved)
|
|
43
|
+
# load "origen/commands/compile.rb"
|
|
44
|
+
# # Pattern generator tests
|
|
45
|
+
# #ARGV = %w(some_pattern -t debug -r approved)
|
|
46
|
+
# #load "#{Origen.top}/lib/origen/commands/generate.rb"
|
|
47
|
+
#
|
|
48
|
+
# if Origen.app.stats.changed_files == 0 &&
|
|
49
|
+
# Origen.app.stats.new_files == 0 &&
|
|
50
|
+
# Origen.app.stats.changed_patterns == 0 &&
|
|
51
|
+
# Origen.app.stats.new_patterns == 0
|
|
52
|
+
#
|
|
53
|
+
# Origen.app.stats.report_pass
|
|
54
|
+
# else
|
|
55
|
+
# Origen.app.stats.report_fail
|
|
56
|
+
# status = 1
|
|
57
|
+
# end
|
|
58
|
+
# puts
|
|
59
|
+
# if @command == "test"
|
|
60
|
+
# Origen.app.unload_target!
|
|
61
|
+
# require "rspec"
|
|
62
|
+
# result = RSpec::Core::Runner.run(['spec'])
|
|
63
|
+
# status = status == 1 ? 1 : result
|
|
64
|
+
# end
|
|
65
|
+
# exit status # Exit with a 1 on the event of a failure per std unix result codes
|
|
66
|
+
|
|
67
|
+
# Always leave an else clause to allow control to fall back through to the
|
|
68
|
+
# Origen command handler.
|
|
69
|
+
else
|
|
70
|
+
# You probably want to also add the your commands to the help shown via
|
|
71
|
+
# origen -h, you can do this by assigning the required text to @application_commands
|
|
72
|
+
# before handing control back to Origen.
|
|
73
|
+
@application_commands = <<-EOT
|
|
74
|
+
tags Build a tags file for this app
|
|
75
|
+
EOT
|
|
76
|
+
# specs Run the specs (tests), -c will enable coverage
|
|
77
|
+
# examples Run the examples (tests), -c will enable coverage
|
|
78
|
+
# test Run both specs and examples, -c will enable coverage
|
|
79
|
+
end
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# This file is used to hook the generators defined in this plugin into the
|
|
2
|
+
# 'origen new' command, it must not be removed or modified
|
|
3
|
+
require 'origen_app_generators'
|
|
4
|
+
require "origen_llm"
|
|
5
|
+
template_dir = File.expand_path('../../app/templates/app_generators', __FILE__)
|
|
6
|
+
OrigenAppGenerators.add_generators(OrigenLlm::AVAILABLE, template_dir: template_dir)
|
data/config/version.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: origen_llm
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Priyavadan Kumar
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-02-21 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: origen
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.60.20
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.60.20
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: origen_app_generators
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.60.20
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.60.20
|
|
41
|
+
description:
|
|
42
|
+
email:
|
|
43
|
+
- priyavadan@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- app/lib/origen_llm.rb
|
|
49
|
+
- app/lib/origen_llm/application.rb
|
|
50
|
+
- app/lib/origen_llm/base.rb
|
|
51
|
+
- app/lib/origen_llm/error_assistant.rb
|
|
52
|
+
- app/lib/origen_llm/error_assistant/client.rb
|
|
53
|
+
- app/lib/origen_llm/error_assistant/prompt.rb
|
|
54
|
+
- app/lib/origen_llm/plugin.rb
|
|
55
|
+
- app/templates/web/index.md.erb
|
|
56
|
+
- app/templates/web/layouts/_basic.html.erb
|
|
57
|
+
- app/templates/web/partials/_navbar.html.erb
|
|
58
|
+
- app/templates/web/release_notes.md.erb
|
|
59
|
+
- config/application.rb
|
|
60
|
+
- config/boot.rb
|
|
61
|
+
- config/commands.rb
|
|
62
|
+
- config/load_generators.rb
|
|
63
|
+
- config/version.rb
|
|
64
|
+
homepage: http://origen-sdk.org/origen_llm
|
|
65
|
+
licenses: []
|
|
66
|
+
metadata: {}
|
|
67
|
+
post_install_message:
|
|
68
|
+
rdoc_options: []
|
|
69
|
+
require_paths:
|
|
70
|
+
- lib
|
|
71
|
+
- app/lib
|
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '2'
|
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: 1.8.11
|
|
82
|
+
requirements: []
|
|
83
|
+
rubygems_version: 3.2.3
|
|
84
|
+
signing_key:
|
|
85
|
+
specification_version: 4
|
|
86
|
+
summary: This plugin enables a simple LLM connector for Origen
|
|
87
|
+
test_files: []
|