flowengine 0.2.1 → 0.3.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.
data/lib/flowengine.rb CHANGED
@@ -1,26 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "flowengine/version"
4
- require_relative "flowengine/errors"
5
- require_relative "flowengine/rules/base"
6
- require_relative "flowengine/rules/contains"
7
- require_relative "flowengine/rules/equals"
8
- require_relative "flowengine/rules/greater_than"
9
- require_relative "flowengine/rules/less_than"
10
- require_relative "flowengine/rules/not_empty"
11
- require_relative "flowengine/rules/all"
12
- require_relative "flowengine/rules/any"
13
- require_relative "flowengine/evaluator"
14
- require_relative "flowengine/transition"
15
- require_relative "flowengine/node"
16
- require_relative "flowengine/introduction"
17
- require_relative "flowengine/definition"
18
- require_relative "flowengine/validation/adapter"
19
- require_relative "flowengine/validation/null_adapter"
20
- require_relative "flowengine/engine"
21
- require_relative "flowengine/dsl"
22
- require_relative "flowengine/graph/mermaid_exporter"
23
- require_relative "flowengine/llm"
3
+ require "zeitwerk"
4
+
5
+ loader = Zeitwerk::Loader.for_gem
6
+ loader.inflector.inflect(
7
+ "flowengine" => "FlowEngine",
8
+ "llm" => "LLM",
9
+ "dsl" => "DSL"
10
+ )
11
+ loader.setup
24
12
 
25
13
  # Declarative flow definition and execution engine for wizards, intake forms, and
26
14
  # multi-step decision graphs. Separates flow logic, data schema, and UI rendering.
@@ -45,11 +33,14 @@ require_relative "flowengine/llm"
45
33
  # engine.current_step_id # => :business_details
46
34
  #
47
35
  module FlowEngine
36
+ # Root directory of the flowengine gem
37
+ ROOT = File.expand_path("..", __dir__)
38
+
48
39
  # Builds an immutable {Definition} from the declarative DSL block.
49
40
  #
50
41
  # @yield context of {DSL::FlowBuilder} (start, step, and rule helpers)
51
42
  # @return [Definition] frozen flow definition with start step and nodes
52
- # @raise [DefinitionError] if no start step or no steps are defined
43
+ # @raise [Errors::DefinitionError] if no start step or no steps are defined
53
44
  def self.define(&)
54
45
  builder = DSL::FlowBuilder.new
55
46
  builder.instance_eval(&)
@@ -61,14 +52,22 @@ module FlowEngine
61
52
  #
62
53
  # @param text [String] Ruby source containing FlowEngine.define { ... }
63
54
  # @return [Definition] the definition produced by evaluating the DSL
64
- # @raise [DefinitionError] on syntax or evaluation errors
55
+ # @raise [Errors::DefinitionError] on syntax or evaluation errors
65
56
  def self.load_dsl(text)
66
57
  # rubocop:disable Security/Eval
67
58
  eval(text, TOPLEVEL_BINDING.dup, "(dsl)", 1)
68
59
  # rubocop:enable Security/Eval
69
60
  rescue SyntaxError => e
70
- raise DefinitionError, "DSL syntax error: #{e.message}"
61
+ raise Errors::DefinitionError, "DSL syntax error: #{e.message}"
71
62
  rescue StandardError => e
72
- raise DefinitionError, "DSL evaluation error: #{e.message}"
63
+ raise Errors::DefinitionError, "DSL evaluation error: #{e.message}"
64
+ end
65
+
66
+ # Resolves a fully-qualified constant name string to the actual constant.
67
+ #
68
+ # @param name [String] e.g. "FlowEngine::LLM::Adapters::AnthropicAdapter"
69
+ # @return [Class, Module]
70
+ def self.constantize(name)
71
+ name.split("::").inject(Object) { |mod, const| mod.const_get(const) }
73
72
  end
74
73
  end
@@ -0,0 +1,25 @@
1
+ models:
2
+ version: "1.0"
3
+ date: "Wed Mar 11 02:35:39 PDT 2026"
4
+ vendors:
5
+ anthropic:
6
+ adapter: "FlowEngine::LLM::Adapters::AnthropicAdapter"
7
+ var: "ANTHROPIC_API_KEY"
8
+ top: "claude-opus-4-6"
9
+ default: "claude-sonnet-4-6"
10
+ fastest: "claude-haiku-4-5-20251001"
11
+ openai:
12
+ adapter: "FlowEngine::LLM::Adapters::OpenAIAdapter"
13
+ var: "OPENAI_API_KEY"
14
+ top: "gpt-5.4"
15
+ default: "gpt-5-mini"
16
+ fastest: "gpt-5-nano"
17
+ gemini:
18
+ adapter: "FlowEngine::LLM::Adapters::GeminiAdapter"
19
+ var: "GEMINI_API_KEY"
20
+ top: "gemini-3.1-pro-preview"
21
+ default: "gemini-2.5-flash"
22
+ fastest: "gemini-2.5-flash-lite"
23
+
24
+
25
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flowengine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: zeitwerk
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
26
40
  - !ruby/object:Gem::Dependency
27
41
  name: rspec
28
42
  requirement: !ruby/object:Gem::Requirement
@@ -115,20 +129,25 @@ files:
115
129
  - exe/flowengine
116
130
  - justfile
117
131
  - lib/flowengine.rb
132
+ - lib/flowengine/clarification_result.rb
118
133
  - lib/flowengine/definition.rb
119
134
  - lib/flowengine/dsl.rb
120
135
  - lib/flowengine/dsl/flow_builder.rb
121
136
  - lib/flowengine/dsl/rule_helpers.rb
122
137
  - lib/flowengine/dsl/step_builder.rb
123
138
  - lib/flowengine/engine.rb
139
+ - lib/flowengine/engine/state_serializer.rb
124
140
  - lib/flowengine/errors.rb
125
141
  - lib/flowengine/evaluator.rb
126
142
  - lib/flowengine/graph/mermaid_exporter.rb
127
143
  - lib/flowengine/introduction.rb
128
144
  - lib/flowengine/llm.rb
129
145
  - lib/flowengine/llm/adapter.rb
146
+ - lib/flowengine/llm/adapters.rb
147
+ - lib/flowengine/llm/auto_client.rb
130
148
  - lib/flowengine/llm/client.rb
131
- - lib/flowengine/llm/openai_adapter.rb
149
+ - lib/flowengine/llm/intake_prompt_builder.rb
150
+ - lib/flowengine/llm/provider.rb
132
151
  - lib/flowengine/llm/sensitive_data_filter.rb
133
152
  - lib/flowengine/llm/system_prompt_builder.rb
134
153
  - lib/flowengine/node.rb
@@ -144,6 +163,7 @@ files:
144
163
  - lib/flowengine/validation/adapter.rb
145
164
  - lib/flowengine/validation/null_adapter.rb
146
165
  - lib/flowengine/version.rb
166
+ - resources/models.yml
147
167
  - resources/prompts/generic-dsl-intake.j2
148
168
  - sig/flowengine.rbs
149
169
  homepage: https://github.com/kigster/flowengine
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ruby_llm"
4
-
5
- module FlowEngine
6
- module LLM
7
- # OpenAI adapter using the ruby_llm gem. Configures the API key
8
- # and delegates chat calls to RubyLLM's conversation interface.
9
- class OpenAIAdapter < Adapter
10
- # @param api_key [String, nil] OpenAI API key; falls back to OPENAI_API_KEY env var
11
- # @raise [LLMError] if no API key is available
12
- def initialize(api_key: nil)
13
- super()
14
- @api_key = api_key || ENV.fetch("OPENAI_API_KEY", nil)
15
- raise LLMError, "OpenAI API key not provided and OPENAI_API_KEY not set" unless @api_key
16
- end
17
-
18
- # @param system_prompt [String] system instructions
19
- # @param user_prompt [String] user's text
20
- # @param model [String] OpenAI model identifier
21
- # @return [String] response content from the LLM
22
- def chat(system_prompt:, user_prompt:, model: "gpt-4o-mini")
23
- configure_ruby_llm!
24
- conversation = RubyLLM.chat(model: model)
25
- response = conversation.with_instructions(system_prompt).ask(user_prompt)
26
- response.content
27
- end
28
-
29
- private
30
-
31
- def configure_ruby_llm!
32
- RubyLLM.configure do |config|
33
- config.openai_api_key = @api_key
34
- end
35
- end
36
- end
37
- end
38
- end