funcrunner 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3adde37e5f80ed54c2a0e9c25b02c3dfd2d36f93309fe3d345f1281f4a2b9c35
4
+ data.tar.gz: d0669779e63f9bdb6e8833cf24b899894b43dd71d1a0e92bf7f131ecfed274b8
5
+ SHA512:
6
+ metadata.gz: 53ecaf8b424eee154588455a1ab64d9df78d33fb3e9aa2ac09e67f544b26d6fa7c47d8080989428ae13a4f110671edd9d41ac90cd788a90cc532a81f7c01c308
7
+ data.tar.gz: 9cfcee3a74b6fab0292c90491ee3786402f8889ecfa76b3a124d6a1adf4e8523cf8f86807d2e04a4dfee20d3663e9c9733354bf9fd0a941e0fe2c57bbe04c71f
data/.idea/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
data/.idea/aws.xml ADDED
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="accountSettings">
4
+ <option name="activeProfile" value="profile:default" />
5
+ <option name="activeRegion" value="us-east-1" />
6
+ <option name="recentlyUsedProfiles">
7
+ <list>
8
+ <option value="profile:default" />
9
+ </list>
10
+ </option>
11
+ <option name="recentlyUsedRegions">
12
+ <list>
13
+ <option value="us-east-1" />
14
+ </list>
15
+ </option>
16
+ </component>
17
+ </project>
@@ -0,0 +1,90 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="ModuleRunConfigurationManager">
4
+ <shared />
5
+ </component>
6
+ <component name="NewModuleRootManager">
7
+ <content url="file://$MODULE_DIR$">
8
+ <sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
9
+ <sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
10
+ <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
11
+ </content>
12
+ <orderEntry type="inheritedJdk" />
13
+ <orderEntry type="sourceFolder" forTests="false" />
14
+ <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
15
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v2.5.23, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.3.4, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="faraday (v2.12.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
18
+ <orderEntry type="library" scope="PROVIDED" name="faraday-net_http (v3.3.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="json (v2.8.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
20
+ <orderEntry type="library" scope="PROVIDED" name="language_server-protocol (v3.17.0.3, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
21
+ <orderEntry type="library" scope="PROVIDED" name="lint_roller (v1.1.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
22
+ <orderEntry type="library" scope="PROVIDED" name="logger (v1.6.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
23
+ <orderEntry type="library" scope="PROVIDED" name="minitest (v5.25.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
24
+ <orderEntry type="library" scope="PROVIDED" name="net-http (v0.5.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
25
+ <orderEntry type="library" scope="PROVIDED" name="parallel (v1.26.3, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
26
+ <orderEntry type="library" scope="PROVIDED" name="parser (v3.3.6.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
27
+ <orderEntry type="library" scope="PROVIDED" name="racc (v1.8.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
28
+ <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
29
+ <orderEntry type="library" scope="PROVIDED" name="rake (v13.2.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
30
+ <orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.9.2, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.66.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
32
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.34.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
33
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-performance (v1.22.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
34
+ <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.13.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
35
+ <orderEntry type="library" scope="PROVIDED" name="semantic_logger (v4.16.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
36
+ <orderEntry type="library" scope="PROVIDED" name="standard (v1.41.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
37
+ <orderEntry type="library" scope="PROVIDED" name="standard-custom (v1.0.2, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
38
+ <orderEntry type="library" scope="PROVIDED" name="standard-performance (v1.5.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
39
+ <orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v2.6.0, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
40
+ <orderEntry type="library" scope="PROVIDED" name="uri (v1.0.1, RVM: ruby-3.3.4 [global]) [gem]" level="application" />
41
+ </component>
42
+ <component name="RakeTasksCache-v2">
43
+ <option name="myRootTask">
44
+ <RakeTaskImpl id="rake">
45
+ <subtasks>
46
+ <RakeTaskImpl description="Build funcrunner-0.1.0.gem into the pkg directory" fullCommand="build" id="build" />
47
+ <RakeTaskImpl id="build">
48
+ <subtasks>
49
+ <RakeTaskImpl description="Generate SHA512 checksum of funcrunner-0.1.0.gem into the checksums directory" fullCommand="build:checksum" id="checksum" />
50
+ </subtasks>
51
+ </RakeTaskImpl>
52
+ <RakeTaskImpl description="Remove any temporary products" fullCommand="clean" id="clean" />
53
+ <RakeTaskImpl description="Remove any generated files" fullCommand="clobber" id="clobber" />
54
+ <RakeTaskImpl description="Build and install funcrunner-0.1.0.gem into system gems" fullCommand="install" id="install" />
55
+ <RakeTaskImpl id="install">
56
+ <subtasks>
57
+ <RakeTaskImpl description="Build and install funcrunner-0.1.0.gem into system gems without network access" fullCommand="install:local" id="local" />
58
+ </subtasks>
59
+ </RakeTaskImpl>
60
+ <RakeTaskImpl description="Create tag v0.1.0 and build and push funcrunner-0.1.0.gem to rubygems.org" fullCommand="release[remote]" id="release[remote]" />
61
+ <RakeTaskImpl description="Lint with the Standard Ruby style guide" fullCommand="standard" id="standard" />
62
+ <RakeTaskImpl id="standard">
63
+ <subtasks>
64
+ <RakeTaskImpl description="Lint and automatically make safe fixes with the Standard Ruby style guide" fullCommand="standard:fix" id="fix" />
65
+ <RakeTaskImpl description="Lint and automatically make fixes (even unsafe ones" fullCommand="standard:fix_unsafely" id="fix_unsafely" />
66
+ </subtasks>
67
+ </RakeTaskImpl>
68
+ <RakeTaskImpl description="Run the test suite" fullCommand="test" id="test" />
69
+ <RakeTaskImpl id="test">
70
+ <subtasks>
71
+ <RakeTaskImpl description="Print out the test command" fullCommand="test:cmd" id="cmd" />
72
+ <RakeTaskImpl description="Show which test files fail when run in isolation" fullCommand="test:isolated" id="isolated" />
73
+ <RakeTaskImpl description="Run the test suite and report the slowest 25 tests" fullCommand="test:slow" id="slow" />
74
+ <RakeTaskImpl description="" fullCommand="test:deps" id="deps" />
75
+ </subtasks>
76
+ </RakeTaskImpl>
77
+ <RakeTaskImpl description="" fullCommand="default" id="default" />
78
+ <RakeTaskImpl description="" fullCommand="release" id="release" />
79
+ <RakeTaskImpl id="release">
80
+ <subtasks>
81
+ <RakeTaskImpl description="" fullCommand="release:guard_clean" id="guard_clean" />
82
+ <RakeTaskImpl description="" fullCommand="release:rubygem_push" id="rubygem_push" />
83
+ <RakeTaskImpl description="" fullCommand="release:source_control_push" id="source_control_push" />
84
+ </subtasks>
85
+ </RakeTaskImpl>
86
+ </subtasks>
87
+ </RakeTaskImpl>
88
+ </option>
89
+ </component>
90
+ </module>
@@ -0,0 +1,17 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <profile version="1.0">
3
+ <option name="myName" value="Project Default" />
4
+ <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
5
+ <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
6
+ <option name="ignoredPackages">
7
+ <value>
8
+ <list size="1">
9
+ <item index="0" class="java.lang.String" itemvalue="dj_database_url" />
10
+ </list>
11
+ </value>
12
+ </option>
13
+ </inspection_tool>
14
+ <inspection_tool class="RbsMissingTypeSignature" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
15
+ <inspection_tool class="RubyQuotedStringsInspection" enabled="false" level="INFORMATION" enabled_by_default="false" />
16
+ </profile>
17
+ </component>
data/.idea/misc.xml ADDED
@@ -0,0 +1,4 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectRootManager" version="2" project-jdk-name="RVM: ruby-3.3.4 [global]" project-jdk-type="RUBY_SDK" />
4
+ </project>
data/.idea/modules.xml ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/funcrunner.iml" filepath="$PROJECT_DIR$/.idea/funcrunner.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
data/.idea/vcs.xml ADDED
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </project>
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/standardrb/standard
3
+ ruby_version: 3.0
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Funcrunner
2
+
3
+ TODO: Delete this and the text below, and describe your gem
4
+
5
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/funcrunner`. To experiment with that code, run `bin/console` for an interactive prompt.
6
+
7
+ ## Installation
8
+
9
+ TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
10
+
11
+ Install the gem and add to the application's Gemfile by executing:
12
+
13
+ ```bash
14
+ bundle add UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
15
+ ```
16
+
17
+ If bundler is not being used to manage dependencies, install the gem by executing:
18
+
19
+ ```bash
20
+ gem install UPDATE_WITH_YOUR_GEM_NAME_IMMEDIATELY_AFTER_RELEASE_TO_RUBYGEMS_ORG
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/funcrunner.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "standard/rake"
9
+
10
+ task default: %i[test standard]
@@ -0,0 +1,236 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ class Application
5
+ attr_accessor :function_registry, :is_running, :logger, :config
6
+
7
+ def initialize
8
+ @function_registry = {}
9
+ @is_running = false
10
+ @logger = FuncRunner.config.logger
11
+ @config = FuncRunner.config
12
+ if @config.api_key.nil?
13
+ raise "Missing Func Runner API key. Set FUNCRUNNER_API_KEY environment variable or use config.api_key="
14
+ end
15
+ end
16
+
17
+ def function(name, &definition)
18
+ function_definition = FunctionDefinition.new(name)
19
+ function_definition.instance_eval(&definition)
20
+ @function_registry[name] = function_definition.to_h
21
+ logger.info("Registered function '#{name}' with params #{function_definition.param_types}")
22
+ end
23
+
24
+ def fetch_run_data(message)
25
+ url = "https://proxy.funcrunner.com/v1/threads/#{message.thread_id}/runs/#{message.run_id}"
26
+ logger.debug("Fetching run data from URL: #{url}", message_id: message.id, run_id: message.run_id, correlation_id: message.correlation_id)
27
+ response = make_request(:get, url, message)
28
+ return JSON.parse(response.body) if response&.status == 200
29
+
30
+ logger.error("Failed to fetch run data", url: url)
31
+ nil
32
+ end
33
+
34
+ def make_request(method, url, message = nil, data = nil)
35
+ headers = {"Authorization" => "Bearer #{@config.api_key}"}
36
+ Faraday.send(method, url, data, headers)
37
+ rescue Faraday::Error => e
38
+ logger.error("HTTP request failed", method: method, url: url, error: e.message, correlation_id: message&.correlation_id || "N/A")
39
+ nil
40
+ end
41
+
42
+ def process_queue_message(message)
43
+ logger.info("Processing queue message", message_id: message.id, correlation_id: message.correlation_id)
44
+ run = fetch_run_data(message)
45
+ return if run.nil?
46
+
47
+ tool_calls = extract_tool_calls(run)
48
+ function_executions = process_tool_calls(tool_calls)
49
+
50
+ result = RunResult.new(run_id: message.run_id, thread_id: message.thread_id, tool_outputs: [])
51
+ function_executions.each do |fe|
52
+ output = execute_function(fe, message)
53
+ if output.is_a?(String) || output.nil?
54
+ result.tool_outputs << {tool_call_id: fe.tool_call_id, output: output}
55
+ else
56
+ logger.error("#{fe.name} returned non-string value. OpenAI expects functions to return a string.")
57
+ end
58
+ end
59
+
60
+ result
61
+ end
62
+
63
+ def execute_function(fe, message)
64
+ unless @function_registry.key?(fe.name)
65
+ logger.error("Function not found in registry", function_name: fe.name, available_functions: @function_registry.keys, message: message.to_h, correlation_id: message.correlation_id)
66
+ raise NotImplementedError, "Function '#{fe.name}' not found in registry."
67
+ end
68
+
69
+ function = @function_registry[fe.name]
70
+ logger.info("Executing function", function_name: fe.name, arguments: fe.arguments, correlation_id: message.correlation_id)
71
+ function.call(**fe.arguments)
72
+ rescue ArgumentError => e
73
+ logger.error("Argument error when calling function", function_name: fe.name, error: e.message, message: message.to_h, correlation_id: message.correlation_id)
74
+ raise "Argument error when calling '#{fe.name}': #{e.message}"
75
+ end
76
+
77
+ def extract_tool_calls(run)
78
+ tool_calls = run.dig("required_action", "submit_tool_outputs", "tool_calls") || []
79
+ tool_calls.is_a?(Array) ? tool_calls : []
80
+ end
81
+
82
+ def process_tool_calls(tool_calls)
83
+ tool_calls.map do |tool_call|
84
+ name = tool_call.dig("function", "name")
85
+ logger.info("Processing function call request", function_name: name, tool_call_id: tool_call["id"])
86
+ arguments = begin
87
+ JSON.parse(tool_call.dig("function", "arguments"))
88
+ rescue
89
+ {}
90
+ end
91
+ FunctionExecution.new(name: name, arguments: arguments, tool_call_id: tool_call["id"])
92
+ end
93
+ end
94
+
95
+ def dequeue_message
96
+ response = make_request(:get, "https://queue.funcrunner.com/messages")
97
+ return unless response&.status == 200
98
+
99
+ messages = JSON.parse(response.body)
100
+ unless messages.empty?
101
+ logger.info("Message dequeued", message_id: messages[0]["id"])
102
+ Message.new(messages[0])
103
+ end
104
+ end
105
+
106
+ def submit_function_results(result)
107
+ logger.info("Submitting function results", run_id: result.run_id, correlation_id: result.thread_id)
108
+ url = "https://proxy.funcrunner.com/v1/threads/#{result.thread_id}/runs/#{result.run_id}/submit_tool_outputs"
109
+ response = make_request(:post, url, nil, result.dump_submission_response)
110
+ if response&.status == 200
111
+ logger.info("Successfully submitted function results", run_id: result.run_id, correlation_id: result.thread_id)
112
+ true
113
+ else
114
+ logger.error("Failed to submit function results", run_id: result.run_id, correlation_id: result.thread_id)
115
+ false
116
+ end
117
+ end
118
+
119
+ def delete_message(message_id, correlation_id)
120
+ logger.info("Deleting message from the queue", message_id: message_id, correlation_id: correlation_id)
121
+ response = make_request(:delete, "https://queue.funcrunner.com/messages/#{message_id}")
122
+ if response&.status == 200
123
+ logger.info("Successfully deleted queue message", message_id: message_id, correlation_id: correlation_id)
124
+ else
125
+ logger.error("Failed to delete message from the queue", message_id: message_id, correlation_id: correlation_id)
126
+ end
127
+ end
128
+
129
+ def configure_assistant
130
+ logger.info("Updating assistant functions...", assistant_id: config.assistant_id)
131
+
132
+ url = "https://proxy.funcrunner.com/v1/assistants/#{config.assistant_id}"
133
+ response = make_request(:get, url)
134
+
135
+ unless response&.status == 200
136
+ logger.error("Failed to fetch assistant", url: url, error: response&.body)
137
+ return
138
+ end
139
+
140
+ assistant = JSON.parse(response.body)
141
+
142
+ # Filter and update existing tools
143
+ updated_tools = assistant["tools"].select { |tool| %w[code_interpreter file_search].any? { |t| tool.include?(t) } }
144
+
145
+ # Generate function specs and append them to the assistant's tools
146
+ function_specs = function_registry.values.map { |func| generate_function_spec(func) }
147
+ assistant["tools"] = updated_tools + function_specs
148
+
149
+ # Remove read-only attributes to avoid errors in the update request
150
+ %w[id object created_at].each { |attr| assistant.delete(attr) }
151
+ assistant.delete("description") if assistant["description"].nil?
152
+
153
+ # Update assistant with new tools
154
+ update_response = make_request(:post, url, nil, assistant.to_json)
155
+ if update_response&.status == 200
156
+ logger.info("Successfully updated assistant functions.", assistant_id: config.assistant_id)
157
+ else
158
+ logger.error("Failed to update assistant", url: url, status_code: update_response&.status, error: update_response&.body)
159
+ end
160
+ end
161
+
162
+ def run
163
+ logger.info("Starting Func Runner application...")
164
+ logger.info("Available functions: #{function_registry.keys.join(", ")}") unless function_registry.empty?
165
+ logger.info("No functions registered.") if function_registry.empty?
166
+ @is_running = true
167
+
168
+ configure_assistant if config.auto_update && config.assistant_id
169
+
170
+ begin
171
+ while @is_running
172
+ message = dequeue_message
173
+ run_result = process_queue_message(message) if message
174
+ submit_function_results(run_result) if run_result
175
+ delete_message(message.id, message.correlation_id) if run_result
176
+ sleep(config.polling_interval)
177
+ end
178
+ rescue Interrupt
179
+ logger.info("Shutting down gracefully...")
180
+ @is_running = false
181
+ end
182
+ end
183
+
184
+ def stop
185
+ @is_running = false
186
+ logger.info("Func Runner application stopped")
187
+ end
188
+
189
+ private
190
+
191
+ # Generate function specification compatible with OpenAI
192
+ def generate_function_spec(func)
193
+ func_name = func[:name]
194
+ {
195
+ "type" => "function",
196
+ "function" => {
197
+ "name" => func_name,
198
+ "description" => func[:desc],
199
+ "parameters" => generate_parameters_schema(func),
200
+ "strict" => true
201
+ }
202
+ }
203
+ end
204
+
205
+ # Generates JSON schema for function parameters
206
+ def generate_parameters_schema(func)
207
+ parameters_schema = {"type" => "object", "properties" => {}}
208
+ required_params = []
209
+
210
+ func[:params]&.each do |name, type|
211
+ parameters_schema["properties"][name] = if type.to_s.downcase.to_sym == :array
212
+ {type: "array", items: {type: "string"}, description: "#{name} parameter"}
213
+ else
214
+ {type: map_type_to_json(type.to_s.downcase.to_sym), description: "#{name} parameter"}
215
+ end
216
+ required_params << name
217
+ end
218
+
219
+ parameters_schema["required"] = required_params unless required_params.empty?
220
+ parameters_schema["additionalProperties"] = false
221
+ parameters_schema
222
+ end
223
+
224
+ # Helper to map Ruby types to JSON-compatible types
225
+ def map_type_to_json(type)
226
+ case type
227
+ when :string then "string"
228
+ when :integer then "number"
229
+ when :float then "number"
230
+ when :boolean then "boolean"
231
+ when :hash then "object"
232
+ else "string"
233
+ end
234
+ end
235
+ end
236
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ class FunctionDefinition
5
+ attr_reader :name, :desc, :param_types, :function_body
6
+
7
+ def initialize(name)
8
+ @name = name
9
+ @param_types = {}
10
+ end
11
+
12
+ # Define expected parameter types
13
+ def params(types)
14
+ @param_types = types
15
+ end
16
+
17
+ def description(desc)
18
+ @desc = desc
19
+ end
20
+
21
+ # Define the function body
22
+ def body(&block)
23
+ @function_body = block
24
+ end
25
+
26
+ # Convert to hash for storage
27
+ def to_h
28
+ {name: name, desc: desc, params: param_types, function: function_body}
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ class FunctionExecution
5
+ attr_accessor :name, :arguments, :tool_call_id
6
+
7
+ def initialize(options = {})
8
+ @name = options[:name]
9
+ @arguments = options[:arguments] || {}
10
+ @tool_call_id = options[:tool_call_id]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ class FunctionExecutionPayload
5
+ attr_accessor :thread_id, :run_id, :function_executions
6
+
7
+ def initialize(options = {})
8
+ @thread_id = options[:thread_id]
9
+ @run_id = options[:run_id]
10
+ @function_executions = options[:function_executions] || []
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ class Message
5
+ attr_accessor :id, :run_id, :thread_id, :integration_id, :correlation_id, :expires_at, :visible_at, :in_flight
6
+
7
+ def initialize(options = {})
8
+ @id = options[:id]
9
+ @run_id = options[:run_id]
10
+ @thread_id = options[:thread_id]
11
+ @integration_id = options[:integration_id]
12
+ @correlation_id = options[:correlation_id]
13
+ @expires_at = options[:expires_at]
14
+ @visible_at = options[:visible_at]
15
+ @in_flight = options[:in_flight]
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ class RunResult
5
+ attr_accessor :run_id, :thread_id, :tool_outputs
6
+
7
+ def initialize(options = {})
8
+ @run_id = options[:run_id]
9
+ @thread_id = options[:thread_id]
10
+ @tool_outputs = options[:tool_outputs] || []
11
+ end
12
+
13
+ def to_json
14
+ { tool_outputs: @tool_outputs }.to_json
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FuncRunner
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "semantic_logger"
4
+ SemanticLogger.add_appender(io: STDOUT, formatter: :json)
5
+
6
+ require_relative "func_runner/version"
7
+ require_relative "func_runner/application"
8
+ require_relative "func_runner/function_definition"
9
+ require_relative "func_runner/function_execution"
10
+ require_relative "func_runner/function_execution_payload"
11
+ require_relative "func_runner/message"
12
+ require_relative "func_runner/run_result"
13
+
14
+ module FuncRunner
15
+ class Error < StandardError; end
16
+
17
+ class Configuration
18
+ attr_accessor :api_key, :assistant_id, :polling_interval, :auto_update, :logger
19
+
20
+ def initialize
21
+ @api_key = ENV["FUNCRUNNER_API_KEY"]
22
+ @assistant_id = nil
23
+ @polling_interval = 5.0
24
+ @auto_update = true
25
+ @logger = SemanticLogger["Func Runner Application"]
26
+ end
27
+ end
28
+
29
+ # Class-level access to configuration
30
+ class << self
31
+ attr_accessor :configuration, :app
32
+
33
+ # Access the configuration instance
34
+ def config
35
+ @configuration ||= Configuration.new
36
+ end
37
+
38
+ def application
39
+ @application ||= FuncRunner::Application.new
40
+ yield @application if block_given?
41
+ end
42
+
43
+ # Allow block-based configuration
44
+ def configure
45
+ yield config if block_given?
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,4 @@
1
+ module Funcrunner
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: funcrunner
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthew Orahood
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-11-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.12'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: semantic_logger
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.16'
41
+ description: Ruby wrapper for Func Runner.
42
+ email:
43
+ - matthew@funcrunner.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".idea/.gitignore"
49
+ - ".idea/aws.xml"
50
+ - ".idea/funcrunner.iml"
51
+ - ".idea/inspectionProfiles/Project_Default.xml"
52
+ - ".idea/misc.xml"
53
+ - ".idea/modules.xml"
54
+ - ".idea/vcs.xml"
55
+ - ".standard.yml"
56
+ - README.md
57
+ - Rakefile
58
+ - lib/func_runner.rb
59
+ - lib/func_runner/application.rb
60
+ - lib/func_runner/function_definition.rb
61
+ - lib/func_runner/function_execution.rb
62
+ - lib/func_runner/function_execution_payload.rb
63
+ - lib/func_runner/message.rb
64
+ - lib/func_runner/run_result.rb
65
+ - lib/func_runner/version.rb
66
+ - sig/funcrunner.rbs
67
+ homepage: https://funcrunner.com
68
+ licenses: []
69
+ metadata:
70
+ homepage_uri: https://funcrunner.com
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 3.0.0
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubygems_version: 3.5.23
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: Ruby wrapper for Func Runner.
90
+ test_files: []