inquirex-llm 0.4.1 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d88efd2e36800946885576819285836d651aec1b90529504f25399a7856b447d
4
- data.tar.gz: 6be4cf2107958061b45840a87e24c954fa9951458b4cbf868a7bfc8368dd3007
3
+ metadata.gz: db7e0d183259c896f2b1b5d9bd6ce1808f3a0c89de415a7129d2da2133a1ea49
4
+ data.tar.gz: dc3a1659f93182d83972dfccaaacbec820509823c293a97de4ac6df596409701
5
5
  SHA512:
6
- metadata.gz: aeb78792e0f106dd619043daf3b3eb21a7e209ad983bf8f5349eefeb74e071b5ca25b11bd445acbb77b0e1926b170347d1ca38a6c75c7d147cbf6d46ffed79dd
7
- data.tar.gz: e4f00de410d54bb8c4a595816e681a0ca4c1d26a2bdc01583ff636a3b2dddaedef6b499af090e6b18f1f62ff64446122ff2529116f9f19512ef349ff615476c9
6
+ metadata.gz: 6b8e8a8c3069ae95d904e3635d3b4947997e812d678dbf562040ae0647563692edef7364977e20ac2eb972d18d3aaeed88f606a1b05fc2d842ba201ff487b748
7
+ data.tar.gz: a3d8a7a89d4f22b7c3420ae1b22114895bee402314b6e4d303dfd3702f8afae1aeb87eac9a35e53090279a188b2d838c56759a8d2cecfc31179006f64d0d8fe7
data/README.md CHANGED
@@ -1,42 +1,31 @@
1
- [![Ruby](https://github.com/inquirex/inquirex-llm/actions/workflows/main.yml/badge.svg)](https://github.com/inquirex/inquirex-llm/actions/workflows/main.yml)  ![Coverage](docs/badges/coverage_badge.svg)
1
+ [![Gem Version](https://badge.fury.io/rb/inquirex-llm.svg)](https://badge.fury.io/rb/inquirex-llm) [![Ruby](https://github.com/inquirex/inquirex-llm/actions/workflows/main.yml/badge.svg)](https://github.com/inquirex/inquirex-llm/actions/workflows/main.yml) ![Coverage](docs/badges/coverage_badge.svg)
2
2
 
3
3
  # inquirex-llm
4
4
 
5
5
  LLM integration verbs for the [Inquirex](https://github.com/inquirex/inquirex) questionnaire engine.
6
6
 
7
- Extends the core DSL with four server-side verbs -- `clarify`, `describe`, `summarize`, and `detour` -- that bridge free-text answers and structured data via LLM processing. Ships with a pluggable adapter interface and a `NullAdapter` for testing.
7
+ Extends the core DSL with a server-side `extract` verb (alias: `clarify`) that turns free-text answers into structured data via LLM processing. Ships with a pluggable adapter interface and a `NullAdapter` for testing. (`describe`, `summarize`, and `detour` are temporarily parked.)
8
8
 
9
9
  `inquirex` is a pure Ruby, declarative, rules-driven questionnaire engine for building conditional intake forms, qualification wizards, and branching surveys.
10
10
 
11
11
  > [!IMPORTANT]
12
12
  >
13
- > Note that `i`
14
- >
15
- > `nquirex` is the base gem of the ecosystem that contains:
13
+ > Note that `inquirex-llm` is part of an entire ecosystem that contains:
16
14
  >
17
15
  > - [`inquirex`](https://github.com/inquirex/inquirex)
18
16
  > - [`inquirex-llm`](https://github.com/inquirex/inquirex-llm)
19
17
  > - [`inquirex-tty`](https://github.com/inquirex/inquirex-)
20
- > - [`inquirex-js`](https://github.com/inquirex/inquirex-js)
18
+ > - [`inquirex-js`](https://github.com/inquirex/inquirex-js) (`npmjs` module [`@kigster/inquirex-js`](https://www.npmjs.com/package/@kigster/inquirex-js))
21
19
  >
22
- > For a presentation on these gems and what they do please watch the [RubySF presentation](https://www.youtube.com/watch?v=iaoKW7Ap3_M&t=1s) and you can also [view the slides form the presentation](https://reinvent.one/images/talks/pdfs/2026.inquirex.pdf).
23
-
24
- ## Status
25
-
26
- - Version: `0.1.0`
27
- - Ruby: `>= 4.0.0`
28
- - Test suite: `111 examples, 0 failures`
29
- - Depends on: `inquirex` (core gem)
30
-
31
- ## Installation
32
-
33
- ```ruby
34
- gem "inquirex-llm"
35
- ```
20
+ > For a presentation about these gems and what they do please watch the [RubySF presentation](https://www.youtube.com/watch?v=iaoKW7Ap3_M&t=1s) and you can also [view the slides form the presentation](https://reinvent.one/images/talks/pdfs/2026.inquirex.pdf).
21
+ >
22
+ > Finally, the SaaS application [qualified.at](https://qualified.at) allows users to leverage the ecosystem by creating their own custom lead intake flows and integrating them on their own sites.
36
23
 
37
24
  ## Usage
38
25
 
39
- `require "inquirex-llm"` injects the LLM verbs into the core `Inquirex.define` DSL. No separate entry point needed.
26
+ `require "inquirex-llm"` injects the LLM verbs into the core `Inquirex.define` DSL.
27
+
28
+ No separate entry point needed.
40
29
 
41
30
  ```ruby
42
31
  require "inquirex"
@@ -51,7 +40,7 @@ definition = Inquirex.define id: "tax-intake-2026", version: "1.0.0" do
51
40
  transition to: :extracted
52
41
  end
53
42
 
54
- clarify :extracted do
43
+ extract :extracted do
55
44
  from :description
56
45
  prompt "Extract structured business information from the description."
57
46
  schema industry: :string,
@@ -60,15 +49,9 @@ definition = Inquirex.define id: "tax-intake-2026", version: "1.0.0" do
60
49
  estimated_revenue: :currency
61
50
  model :claude_sonnet
62
51
  temperature 0.2
63
- transition to: :summary
64
- end
65
-
66
- summarize :summary do
67
- from_all
68
- prompt "Summarize this client's tax situation and flag complexity concerns."
69
52
  transition to: :done
70
53
  end
71
-
54
+
72
55
  say :done do
73
56
  text "Thank you! We'll be in touch."
74
57
  end
@@ -77,14 +60,14 @@ end
77
60
 
78
61
  All core verbs (`ask`, `say`, `header`, `btw`, `warning`, `confirm`) and widget hints work alongside LLM verbs in the same `Inquirex.define` block.
79
62
 
80
- ## LLM Verbs
63
+ ## Currently Supported LLM Verbs
81
64
 
82
- ### `clarify`
65
+ ### `extract` (alias: `clarify`)
83
66
 
84
- Extract structured data from a free-text answer. Requires `from`, `prompt`, and `schema`.
67
+ Extract structured data from a free-text answer. Requires `from` (or `from_all`), `prompt`, and `schema`. The stored/serialized verb is always `"extract"`; `clarify` is a DSL-only alias.
85
68
 
86
69
  ```ruby
87
- clarify :business_extracted do
70
+ extract :business_extracted do
88
71
  from :business_description
89
72
  prompt "Extract structured business information."
90
73
  schema industry: :string, employee_count: :integer, revenue: :currency
@@ -95,57 +78,20 @@ clarify :business_extracted do
95
78
  end
96
79
  ```
97
80
 
98
- ### `describe`
99
-
100
- Generate natural-language text from structured data. Requires `from` and `prompt`. No schema needed.
101
-
102
- ```ruby
103
- describe :business_narrative do
104
- from :business_extracted
105
- prompt "Write a brief narrative of this business for the intake report."
106
- transition to: :next_step
107
- end
108
- ```
109
-
110
- ### `summarize`
111
-
112
- Produce a summary of all or selected answers. Use `from_all` to pass everything, or `from` to select specific steps.
113
-
114
- ```ruby
115
- summarize :intake_summary do
116
- from_all
117
- prompt "Summarize this client's tax situation."
118
- transition to: :review
119
- end
120
- ```
121
-
122
- ### `detour`
123
-
124
- Dynamically generate follow-up questions based on an answer. The server adapter handles presenting the generated questions and collecting responses. Requires `from`, `prompt`, and `schema`.
125
-
126
- ```ruby
127
- detour :followup do
128
- from :description
129
- prompt "Generate 2-3 follow-up questions to clarify the tax situation."
130
- schema questions: :array, answers: :hash
131
- transition to: :next_step
132
- end
133
- ```
134
-
135
81
  ## DSL Methods (inside LLM verb blocks)
136
82
 
137
- | Method | Purpose | Required |
138
- |--------|---------|----------|
139
- | `prompt "..."` | LLM prompt template | Always |
140
- | `schema key: :type, ...` | Expected output structure | `clarify`, `detour` |
141
- | `from :step_id` | Source step(s) whose answers feed the LLM | `clarify`, `describe`, `detour` |
142
- | `from_all` | Pass all collected answers to the LLM | Alternative to `from` |
143
- | `model :claude_sonnet` | Optional model hint for the adapter | No |
144
- | `temperature 0.3` | Optional sampling temperature | No |
145
- | `max_tokens 1024` | Optional max output tokens | No |
146
- | `fallback { \|answers\| ... }` | Server-side fallback (stripped from JSON) | No |
147
- | `transition to: :step` | Conditional transition (same as core) | No |
148
- | `skip_if rule` | Skip step when condition is true | No |
83
+ | Method | Purpose | Required |
84
+ | ------------------------------ | ----------------------------------------- | ----------------------------- |
85
+ | `prompt "..."` | LLM prompt template | Always |
86
+ | `schema key: :type, ...` | Expected output structure | `extract` |
87
+ | `from :step_id` | Source step(s) whose answers feed the LLM | `extract` (or use `from_all`) |
88
+ | `from_all` | Pass all collected answers to the LLM | Alternative to `from` |
89
+ | `model :claude_sonnet` | Optional model hint for the adapter | No |
90
+ | `temperature 0.3` | Optional sampling temperature | No |
91
+ | `max_tokens 1024` | Optional max output tokens | No |
92
+ | `fallback { \|answers\| ... }` | Server-side fallback (stripped from JSON) | No |
93
+ | `transition to: :step` | Conditional transition (same as core) | No |
94
+ | `skip_if rule` | Skip step when condition is true | No |
149
95
 
150
96
  ## Engine Integration
151
97
 
@@ -176,16 +122,14 @@ result = adapter.call(engine.current_step)
176
122
 
177
123
  ## Built-in Adapters
178
124
 
179
- | Class | Provider | API | Auth | Key env var |
180
- |------------------------------------|-----------|---------------------------------------|-----------------------------|-----------------------|
181
- | `Inquirex::LLM::NullAdapter` | — | none (placeholders) | none | — |
182
- | `Inquirex::LLM::AnthropicAdapter` | Anthropic | `/v1/messages` | `x-api-key` header | `ANTHROPIC_API_KEY` |
183
- | `Inquirex::LLM::OpenAIAdapter` | OpenAI | `/v1/chat/completions` (JSON mode) | `Authorization: Bearer …` | `OPENAI_API_KEY` |
125
+ | Class | Provider | API | Auth | Key env var |
126
+ | --------------------------------------- | --------- | ---------------------------------- | ------------------------- | ------------------- |
127
+ | `Inquirex::LLM::NullAdapter` | — | none (placeholders) | none | — |
128
+ | `Inquirex::LLM::AnthropicAdapter` | Anthropic | `/v1/messages` | `x-api-key` header | `ANTHROPIC_API_KEY` |
129
+ | `Inquirex::LLM::OpenAIAdapter` | OpenAI | `/v1/chat/completions` (JSON mode) | `Authorization: Bearer …` | `OPENAI_API_KEY` |
130
+ | `Inquirex::LLM::LittleLLMAdapter` (TBD) | Any | OpenAI Compatible API | OpenAI Compatible Auth | Provider Specific |
184
131
 
185
- Both real adapters use `net/http` (stdlib, no extra dependency), inject the
186
- declared `schema` into the system prompt as a strict JSON contract, and raise
187
- `Inquirex::LLM::Errors::AdapterError` on HTTP / parse failures and
188
- `SchemaViolationError` when the model's output is missing declared fields.
132
+ The Anthropic and OpenAI adapters use `net/http` (stdlib, no extra dependency), inject the declared `schema` into the system prompt as a strict JSON contract, and raise `Inquirex::LLM::Errors::AdapterError` on HTTP / parse failures and `SchemaViolationError` when the model's output is missing declared fields.
189
133
 
190
134
  ### AnthropicAdapter
191
135
 
@@ -196,8 +140,7 @@ adapter = Inquirex::LLM::AnthropicAdapter.new(
196
140
  )
197
141
  ```
198
142
 
199
- Recognized `model :symbol` values in the DSL: `:claude_sonnet`,
200
- `:claude_haiku`, `:claude_opus` (mapped to the current concrete model ids).
143
+ Recognized `model :symbol` values in the DSL: `:claude_sonnet`, `:claude_haiku`, `:claude_opus` (mapped to the current concrete model ids).
201
144
 
202
145
  ### OpenAIAdapter
203
146
 
@@ -208,18 +151,11 @@ adapter = Inquirex::LLM::OpenAIAdapter.new(
208
151
  )
209
152
  ```
210
153
 
211
- Uses Chat Completions with `response_format: { type: "json_object" }` so the
212
- model is constrained to return valid JSON. Recognized DSL symbols: `:gpt_4o`,
213
- `:gpt_4o_mini`, `:gpt_4_1`, `:gpt_4_1_mini`. For cross-provider portability,
214
- the adapter also accepts the Claude symbols (`:claude_sonnet` → `gpt-4o` etc.)
215
- so a flow file that says `model :claude_sonnet` runs unchanged against either
216
- provider.
154
+ Uses Chat Completions with `response_format: { type: "json_object" }` so the model is constrained to return valid JSON. Recognized DSL symbols: `:gpt_4o`, `:gpt_4o_mini`, `:gpt_4_1`, `:gpt_4_1_mini`. For cross-provider portability, the adapter also accepts the Claude symbols (`:claude_sonnet` → `gpt-4o` etc.) so a flow file that says `model :claude_sonnet` runs unchanged against either provider.
217
155
 
218
156
  ## LLM-assisted Pre-fill Pattern
219
157
 
220
- A common use case: ask *one* open-ended question, let the LLM extract answers
221
- for *many* downstream questions, and only prompt the user for what the LLM
222
- couldn't determine. This is what the core engine's `Engine#prefill!` is for:
158
+ A common use case: ask *one* open-ended question, let the LLM extract answers for *many* downstream questions, and only prompt the user for what the LLM couldn't determine. This is what the core engine's `Engine#prefill!` is for:
223
159
 
224
160
  ```ruby
225
161
  definition = Inquirex.define id: "tax-intake" do
@@ -231,7 +167,7 @@ definition = Inquirex.define id: "tax-intake" do
231
167
  transition to: :extracted
232
168
  end
233
169
 
234
- clarify :extracted do
170
+ extract :extracted do
235
171
  from :describe
236
172
  prompt "Extract: filing_status, dependents, income_types, state_filing."
237
173
  schema filing_status: :string,
@@ -256,7 +192,7 @@ definition = Inquirex.define id: "tax-intake" do
256
192
  skip_if not_empty(:dependents)
257
193
  transition to: :income_types
258
194
  end
259
- # …and so on for every field in the clarify schema
195
+ # …and so on for every field in the extract schema
260
196
  end
261
197
 
262
198
  engine = Inquirex::Engine.new(definition)
@@ -272,12 +208,7 @@ engine.prefill!(result) # splats into top-level answers
272
208
  # whichever field the LLM couldn't fill in.
273
209
  ```
274
210
 
275
- `Engine#prefill!` is non-destructive (won't clobber an answer the user already
276
- gave), ignores `nil`/empty values so they don't spuriously trigger
277
- `not_empty`, and auto-advances past any step whose `skip_if` now evaluates
278
- true. See [examples/09_tax_preparer_llm.rb](../inquirex-tty/examples/09_tax_preparer_llm.rb)
279
- for a complete runnable flow, or the repo-level `demo_llm_intake.rb` for a
280
- scripted end-to-end walkthrough.
211
+ `Engine#prefill!` is non-destructive (won't clobber an answer the user already gave), ignores `nil`/empty values so they don't spuriously trigger `not_empty`, and auto-advances past any step whose `skip_if` now evaluates true. See [examples/09_tax_preparer_llm.rb](../inquirex-tty/examples/09_tax_preparer_llm.rb) for a complete runnable flow, or the repo-level `demo_llm_intake.rb` for a scripted end-to-end walkthrough.
281
212
 
282
213
  ## JSON Serialization
283
214
 
@@ -285,9 +216,9 @@ LLM steps serialize with `"requires_server": true` so the JS widget knows to rou
285
216
 
286
217
  ```json
287
218
  {
288
- "verb": "clarify",
219
+ "verb": "extract",
289
220
  "requires_server": true,
290
- "transitions": [{ "to": "summary", "requires_server": true }],
221
+ "transitions": [{ "to": "next_step", "requires_server": true }],
291
222
  "llm": {
292
223
  "prompt": "Extract structured business information.",
293
224
  "schema": {
@@ -328,6 +259,47 @@ end
328
259
 
329
260
  The base class provides `#source_answers` (gathers relevant answers) and `#validate_output!` (checks schema conformance).
330
261
 
262
+ ## Future Possible LLM Verbs
263
+
264
+ ### `describe`
265
+
266
+ Generate natural-language text from structured data. Requires `from` and `prompt`. No schema needed.
267
+
268
+ ```ruby
269
+ describe :business_narrative do
270
+ from :business_extracted
271
+ prompt "Write a brief narrative of this business for the intake report."
272
+ transition to: :next_step
273
+ end
274
+ ```
275
+
276
+ ### `summarize`
277
+
278
+ Produce a summary of all or selected answers. Use `from_all` to pass everything, or `from` to select specific steps.
279
+
280
+ ```ruby
281
+ summarize :intake_summary do
282
+ from_all
283
+ prompt "Summarize this client's tax situation."
284
+ transition to: :review
285
+ end
286
+ ```
287
+
288
+ ### `detour` (parked)
289
+
290
+ Dynamically generate follow-up questions based on an answer. The server adapter handles presenting the generated questions and collecting responses. Requires `from`, `prompt`, and `schema`.
291
+
292
+ ```ruby
293
+ detour :followup do
294
+ from :description
295
+ prompt "Generate 2-3 follow-up questions to clarify the tax situation."
296
+ schema questions: :array, answers: :hash
297
+ transition to: :next_step
298
+ end
299
+ ```
300
+
301
+ ##
302
+
331
303
  ## Development
332
304
 
333
305
  ```bash
@@ -338,4 +310,8 @@ bundle exec rubocop
338
310
 
339
311
  ## License
340
312
 
341
- MIT. See [LICENSE.txt](LICENSE.txt).
313
+ © 2026 Konstantin Gredeskoul.
314
+
315
+ Distributed under the MIT License.
316
+
317
+ See [LICENSE.txt](LICENSE.txt) for details.
@@ -15,7 +15,7 @@
15
15
  <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
16
16
  <text x="31.5" y="15" fill="#010101" fill-opacity=".3">coverage</text>
17
17
  <text x="31.5" y="14">coverage</text>
18
- <text x="80" y="15" fill="#010101" fill-opacity=".3">99%</text>
19
- <text x="80" y="14">99%</text>
18
+ <text x="80" y="15" fill="#010101" fill-opacity=".3">98%</text>
19
+ <text x="80" y="14">98%</text>
20
20
  </g>
21
21
  </svg>
@@ -28,7 +28,7 @@ module Inquirex
28
28
  #
29
29
  # @param node [LLM::Node] the LLM step to process
30
30
  # @param answers [Hash] current collected answers
31
- # @return [Hash, String] structured output (for clarify/detour) or text (for describe/summarize)
31
+ # @return [Hash, String] structured output (for extract) or text (when no schema)
32
32
  # @raise [Errors::AdapterError] if the LLM call fails
33
33
  # @raise [Errors::SchemaViolationError] if output doesn't match schema
34
34
  def call(node, answers)
@@ -5,7 +5,7 @@ module Inquirex
5
5
  module DSL
6
6
  # Mixin that adds LLM verb methods to Inquirex::DSL::FlowBuilder.
7
7
  # Included automatically when `require "inquirex-llm"` is called,
8
- # so that `Inquirex.define` gains clarify/describe/summarize/detour
8
+ # so that `Inquirex.define` gains `extract` (and its `clarify` alias)
9
9
  # without needing a separate entry point.
10
10
  #
11
11
  # All core verbs (ask, say, header, btw, warning, confirm) remain
@@ -15,34 +15,36 @@ module Inquirex
15
15
  # structured data matching the declared schema.
16
16
  #
17
17
  # @param id [Symbol] step id
18
- def clarify(id, &)
19
- add_llm_step(id, :clarify, &)
18
+ def extract(id, &)
19
+ add_llm_step(id, :extract, &)
20
20
  end
21
21
 
22
- # Defines an LLM description step: takes structured data and produces
23
- # natural-language text.
24
- #
25
- # @param id [Symbol] step id
26
- def describe(id, &)
27
- add_llm_step(id, :describe, &)
28
- end
22
+ alias clarify extract
29
23
 
30
- # Defines an LLM summarization step: takes all or selected answers and
31
- # produces a textual summary.
32
- #
33
- # @param id [Symbol] step id
34
- def summarize(id, &)
35
- add_llm_step(id, :summarize, &)
36
- end
24
+ # # Defines an LLM description step: takes structured data and produces
25
+ # # natural-language text.
26
+ # #
27
+ # # @param id [Symbol] step id
28
+ # def describe(id, &)
29
+ # add_llm_step(id, :describe, &)
30
+ # end
37
31
 
38
- # Defines an LLM detour step: based on an answer, dynamically generates
39
- # follow-up questions. The server adapter handles presenting the generated
40
- # questions and collecting responses.
41
- #
42
- # @param id [Symbol] step id
43
- def detour(id, &)
44
- add_llm_step(id, :detour, &)
45
- end
32
+ # # Defines an LLM summarization step: takes all or selected answers and
33
+ # # produces a textual summary.
34
+ # #
35
+ # # @param id [Symbol] step id
36
+ # def summarize(id, &)
37
+ # add_llm_step(id, :summarize, &)
38
+ # end
39
+
40
+ # # Defines an LLM detour step: based on an answer, dynamically generates
41
+ # # follow-up questions. The server adapter handles presenting the generated
42
+ # # questions and collecting responses.
43
+ # #
44
+ # # @param id [Symbol] step id
45
+ # def detour(id, &)
46
+ # add_llm_step(id, :detour, &)
47
+ # end
46
48
 
47
49
  private
48
50
 
@@ -8,7 +8,7 @@ module Inquirex
8
8
  # while inheriting transition and skip_if from the core StepBuilder.
9
9
  #
10
10
  # @example
11
- # clarify :business_extracted do
11
+ # extract :business_extracted do
12
12
  # from :business_description
13
13
  # prompt "Extract structured business info."
14
14
  # schema industry: :string, employee_count: :integer
@@ -112,7 +112,7 @@ module Inquirex
112
112
  @skip_if = rule
113
113
  end
114
114
 
115
- # Optional display text (used by describe/summarize for user-visible labels).
115
+ # Optional display text (user-visible label for the step).
116
116
  #
117
117
  # @param content [String]
118
118
  def question(content)
@@ -159,15 +159,20 @@ module Inquirex
159
159
  def validate!(id)
160
160
  raise Errors::DefinitionError, "LLM step #{id.inspect} requires a prompt" if @prompt.nil?
161
161
 
162
- if %i[clarify detour].include?(@verb) && @schema_fields.empty?
162
+ # Schema required for extract (and formerly detour).
163
+ if %i[extract].include?(@verb) && @schema_fields.empty?
164
+ # if %i[extract detour].include?(@verb) && @schema_fields.empty?
163
165
  raise Errors::DefinitionError,
164
166
  "LLM step #{id.inspect} (#{@verb}) requires a schema"
165
167
  end
166
168
 
167
- return unless @from_steps.empty? && !@from_all && @verb != :summarize
169
+ return unless @from_steps.empty? && !@from_all
170
+ # return unless @from_steps.empty? && !@from_all && @verb != :summarize
168
171
 
169
- # clarify/describe/detour should reference source steps or from_all
170
- return unless %i[clarify describe detour].include?(@verb)
172
+ # extract (and formerly describe/detour) should reference source steps or from_all
173
+ return unless %i[extract].include?(@verb)
174
+
175
+ # return unless %i[extract describe detour].include?(@verb)
171
176
 
172
177
  raise Errors::DefinitionError,
173
178
  "LLM step #{id.inspect} (#{@verb}) requires `from` or `from_all`"
@@ -7,16 +7,16 @@ module Inquirex
7
7
  # step references, and model configuration.
8
8
  #
9
9
  # LLM verbs:
10
- # :clarify — extract structured data from a free-text answer
11
- # :describe — generate natural-language text from structured data
12
- # :summarize — produce a summary of all or selected answers
13
- # :detour — dynamically generate follow-up questions based on an answer
10
+ # :extract — extract structured data from a free-text answer
11
+ # # :describe — generate natural-language text from structured data
12
+ # # :summarize — produce a summary of all or selected answers
13
+ # # :detour — dynamically generate follow-up questions based on an answer
14
14
  #
15
15
  # All LLM nodes are collecting (they produce answers) and require server
16
16
  # round-trips. The frontend shows a "thinking" state while the server processes.
17
17
  #
18
18
  # @attr_reader prompt [String] LLM prompt template
19
- # @attr_reader schema [Schema, nil] expected output structure (required for clarify/detour)
19
+ # @attr_reader schema [Schema, nil] expected output structure (required for extract)
20
20
  # @attr_reader from_steps [Array<Symbol>] source step ids whose answers feed the LLM
21
21
  # @attr_reader from_all [Boolean] whether to pass all collected answers to the LLM
22
22
  # @attr_reader model [Symbol, nil] optional model hint (e.g. :claude_sonnet)
@@ -24,7 +24,8 @@ module Inquirex
24
24
  # @attr_reader max_tokens [Integer, nil] optional max output tokens
25
25
  # @attr_reader fallback [Proc, nil] server-side fallback (stripped from JSON)
26
26
  class Node < Inquirex::Node
27
- LLM_VERBS = %i[clarify describe summarize detour].freeze
27
+ LLM_VERBS = %i[extract].freeze
28
+ # LLM_VERBS = %i[extract describe summarize detour].freeze
28
29
 
29
30
  attr_reader :prompt,
30
31
  :schema,
@@ -89,7 +90,8 @@ module Inquirex
89
90
  # @param hash [Hash]
90
91
  # @return [LLM::Node]
91
92
  def self.from_h(id, hash)
92
- verb = hash["verb"] || hash[:verb]
93
+ verb = hash["verb"] || hash[:verb]
94
+ verb = :extract if verb.to_s == "clarify" # DSL alias; normalize wire format
93
95
  question = hash["question"] || hash[:question]
94
96
  text = hash["text"] || hash[:text]
95
97
  transitions_data = hash["transitions"] || hash[:transitions] || []
@@ -5,13 +5,13 @@ module Inquirex
5
5
  # Test adapter that returns schema-conformant placeholder values without
6
6
  # calling any LLM API. Useful for testing flows that include LLM steps.
7
7
  #
8
- # For clarify/detour steps with a schema, returns a hash of default values
9
- # matching each field's declared type. For describe/summarize steps, returns
8
+ # For extract steps with a schema, returns a hash of default values
9
+ # matching each field's declared type. Without a schema, returns
10
10
  # a placeholder string.
11
11
  #
12
12
  # @example
13
13
  # adapter = Inquirex::LLM::NullAdapter.new
14
- # result = adapter.call(clarify_node, answers)
14
+ # result = adapter.call(extract_node, answers)
15
15
  # # => { industry: "", employee_count: 0, ... }
16
16
  class NullAdapter < Adapter
17
17
  TYPE_DEFAULTS = {
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Inquirex
4
4
  module LLM
5
- VERSION = "0.4.1"
5
+ VERSION = "0.5.0"
6
6
  end
7
7
  end
data/lib/inquirex/llm.rb CHANGED
@@ -17,11 +17,11 @@ require_relative "llm/dsl/flow_builder"
17
17
  module Inquirex
18
18
  # LLM integration layer for Inquirex flows.
19
19
  #
20
- # Extends the core DSL with four LLM-powered verbs that run server-side:
21
- # - clarify — extract structured data from free-text answers
22
- # - describe — generate natural-language text from structured data
23
- # - summarize — produce a summary of all or selected answers
24
- # - detour — dynamically generate follow-up questions
20
+ # Extends the core DSL with LLM-powered verbs that run server-side:
21
+ # - extract — extract structured data from free-text answers (`clarify` is an alias)
22
+ # # - describe — generate natural-language text from structured data
23
+ # # - summarize — produce a summary of all or selected answers
24
+ # # - detour — dynamically generate follow-up questions
25
25
  #
26
26
  # LLM calls never happen on the frontend. Steps are marked `requires_server: true`
27
27
  # in the JSON wire format so the JS widget knows to round-trip to the server.
@@ -33,7 +33,7 @@ module Inquirex
33
33
  # Inquirex.define id: "intake" do
34
34
  # start :description
35
35
  # ask(:description) { type :text; question "Describe your business."; transition to: :extracted }
36
- # clarify(:extracted) { from :description; prompt "Extract info."; schema name: :string; transition to: :done }
36
+ # extract(:extracted) { from :description; prompt "Extract info."; schema name: :string; transition to: :done }
37
37
  # say(:done) { text "Done!" }
38
38
  # end
39
39
  module LLM
@@ -41,5 +41,5 @@ module Inquirex
41
41
  end
42
42
 
43
43
  # Inject LLM verbs into the core FlowBuilder so that Inquirex.define
44
- # gains clarify/describe/summarize/detour when this gem is loaded.
44
+ # gains extract (and clarify as an alias) when this gem is loaded.
45
45
  Inquirex::DSL::FlowBuilder.include(Inquirex::LLM::DSL::FlowBuilderExtension)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inquirex-llm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -23,10 +23,10 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0.4'
26
- description: Extends the Inquirex DSL with four LLM-powered verbs clarify, describe,
27
- summarize, and detour — that run server-side to extract structured data, generate
28
- text, and dynamically branch flows. Pluggable adapter interface keeps the gem LLM-agnostic;
29
- a NullAdapter ships for testing.
26
+ description: 'Extends the Inquirex DSL with an LLM-powered `extract` verb (alias:
27
+ `clarify`) that runs server-side to turn free-text answers into structured data.
28
+ Pluggable adapter interface keeps the gem LLM-agnostic; a NullAdapter ships for
29
+ testing.'
30
30
  email:
31
31
  - kigster@gmail.com
32
32
  executables: