inquirex 0.12.0 → 0.12.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 +4 -4
- data/README.md +56 -1
- data/lib/inquirex/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fe9f05cd41bfb91eb6ebf5c75a4a1f8a7323e761516fa4ba303d1df1ad539c9e
|
|
4
|
+
data.tar.gz: bfc9557af719b4eb03ca651c84d72d9c3d3d7f477763422dbce679caa4c80b2f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8bf741953e3400e1ce9ac050e5ee3bfc521c52db204d2c2d21c45ae5e80b0cdedff71c6fef3f82c86c5a80c98c2ce85aa0c4f52925047ec8d31c188284fec9fd
|
|
7
|
+
data.tar.gz: 1bf3e9c4fc15c4c4eb1e2f6efdc2fb41a50c39eb52f18f46bb2012f1377da58ab7e55f27f3300185095d2e0039e383d4c572ccc1b3e0239b8e2e65528bcb31f5
|
data/README.md
CHANGED
|
@@ -311,7 +311,9 @@ Inquirex.define id: "depreciation-help" do
|
|
|
311
311
|
accumulator :transcript, type: :text
|
|
312
312
|
start :intro
|
|
313
313
|
|
|
314
|
-
say(:intro)
|
|
314
|
+
say(:intro) do
|
|
315
|
+
text "Depreciation spreads an asset's cost over its useful life."; transition to: :asset_kind
|
|
316
|
+
end
|
|
315
317
|
ask :asset_kind do
|
|
316
318
|
type :enum
|
|
317
319
|
question "What kind of asset?"
|
|
@@ -471,6 +473,7 @@ Behavior:
|
|
|
471
473
|
- Use `finished?` to detect completion
|
|
472
474
|
- Use `total(:price)` / `totals` to read running totals
|
|
473
475
|
- Use `to_state` / `.from_state` for persistence/resume (totals included)
|
|
476
|
+
- Use `back` to undo the last answer or skip and re-ask that question (see [Going Back](#going-back))
|
|
474
477
|
- Use `prefill!(hash)` to merge externally-supplied answers into the state, e.g. fields extracted by an LLM from a free-text answer (see [inquirex-llm](#extension-gems)). Existing answers are preserved; `nil` and empty values are ignored so they don't spuriously satisfy `not_empty` rules. The engine auto-advances past any newly-skippable step.
|
|
475
478
|
|
|
476
479
|
```ruby
|
|
@@ -552,6 +555,57 @@ On the wire, step JSON carries `"required": false` (omitted when true, like othe
|
|
|
552
555
|
> [!NOTE]
|
|
553
556
|
> **`skip_if` is not the same thing.** A `skip_if` rule is *flow logic*: the definition elides the step from the path automatically, no default kicks in, and the step is **not** added to `engine.skipped` — it was never presented, so the user cannot have declined it. `Engine#skip` is a *user action* on a question that was presented. See [`docs/design/required-and-skip.md`](docs/design/required-and-skip.md) for the full design.
|
|
554
557
|
|
|
558
|
+
## Going Back
|
|
559
|
+
|
|
560
|
+
`Engine#back` undoes the last `answer` or `skip` and returns the engine to that question, so a renderer can offer a **Back** control. Every `answer`, `skip` and `advance` pushes a snapshot of the full state before it mutates, and `back` restores the most recent snapshot taken at a *collecting* step — display steps (`say`, `header`, `btw`, `warning`) are stepped over, since there is nothing to re-answer there.
|
|
561
|
+
|
|
562
|
+
```ruby
|
|
563
|
+
engine.answer("married") # :filing_status -> :dependents
|
|
564
|
+
engine.answer(2) # :dependents -> :state
|
|
565
|
+
engine.back # => true; back at :dependents
|
|
566
|
+
engine.previous_answer(:dependents) # => 2, pre-fill the input with it
|
|
567
|
+
engine.back # => true; back at :filing_status
|
|
568
|
+
engine.back # => false; nothing to undo
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
What `back` restores is the snapshot, not a replay: answers, running totals (including `:text` transcripts), `skipped`, prefilled suggestions, history and completion metadata all come back exactly as they were. Replaying answers would not be equivalent — a Proc `default` or a `prefill!` suggestion does not re-derive.
|
|
572
|
+
|
|
573
|
+
- `engine.can_back?` says whether `back` would move; use it to decide whether to show the control at all.
|
|
574
|
+
- `engine.previous_answer(step_id)` returns the step's current answer if it has one, otherwise the last answer `back` took away from it — so the question can be re-asked with the old value filled in.
|
|
575
|
+
- `engine.current_default` resolves the current step's default as `skip` would (a Proc default is called with the answers so far), for pre-filling.
|
|
576
|
+
- `back` keeps the validator and any `after_completion` hooks registered on the engine.
|
|
577
|
+
|
|
578
|
+
> [!NOTE]
|
|
579
|
+
> The undo stack is **session-local** and is deliberately left out of `to_state`. An engine rebuilt with `.from_state` starts with nothing to go back to; persisting the stack would nest every earlier state inside each saved one.
|
|
580
|
+
|
|
581
|
+
## Headless Runs
|
|
582
|
+
|
|
583
|
+
`Inquirex::Headless` runs a flow to the end from a hash of preset answers — no terminal, no prompt, no LLM adapter. It is the driver behind `inquirex-tty run --answers` and `--yes`, and the simplest way to exercise a flow in tests and CI.
|
|
584
|
+
|
|
585
|
+
```ruby
|
|
586
|
+
run = Inquirex::Headless.new(
|
|
587
|
+
definition,
|
|
588
|
+
answers: { filing_status: "single", state: "CA" }, # string keys (from JSON/YAML) are fine too
|
|
589
|
+
yes: true # take each unanswered step's default
|
|
590
|
+
)
|
|
591
|
+
results = run.call
|
|
592
|
+
|
|
593
|
+
results[:path_taken] # => [:filing_status, :dependents, :state, :done]
|
|
594
|
+
results[:answers] # => answers_with_metadata (includes :skipped, :completion_metadata)
|
|
595
|
+
results[:steps_completed] # => 4 (steps visited, display steps included)
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
For each step, in order:
|
|
599
|
+
|
|
600
|
+
1. A display step advances silently.
|
|
601
|
+
1. A step present in `answers:` is answered with that value verbatim — an LLM step included: the value stands in for the adapter's output and is **not** splatted into other answers, so put downstream answers in the hash directly.
|
|
602
|
+
1. Otherwise, with `yes: true`, a step with a `default` is answered with it (Proc defaults are resolved against the answers so far).
|
|
603
|
+
1. Otherwise an optional step is skipped, recording its default exactly as `Engine#skip` does.
|
|
604
|
+
1. Otherwise, with `yes: true`, a required LLM step with no default is answered with `nil`.
|
|
605
|
+
1. Otherwise the run stops with `Inquirex::Headless::MissingAnswer` (an `Errors::EngineError` carrying `#step_id`).
|
|
606
|
+
|
|
607
|
+
Answers reach the engine only through `answer` and `skip`, never `prefill!` — a prefilled multi-select is a *suggestion* that no `skip_if` rule can see, which would leave such a step waiting for an answer nobody is there to give. Register `after_completion` hooks on `run.engine` before `call` to attach completion metadata.
|
|
608
|
+
|
|
555
609
|
## Completion Metadata
|
|
556
610
|
|
|
557
611
|
When a flow finishes, the engine guarantees a `CompletionMetadata` — an OpenStruct describing how the answers were collected. Only `engine` and `engine_version` are required members; rendering front-ends attach richer environment details from an `after_completion` hook:
|
|
@@ -735,6 +789,7 @@ Common exceptions under `Inquirex::Errors`:
|
|
|
735
789
|
- `ValidationError`
|
|
736
790
|
- `NonCollectingStepError`
|
|
737
791
|
- `RequiredStepError`
|
|
792
|
+
- `Headless::MissingAnswer`
|
|
738
793
|
- `SendEmailError`
|
|
739
794
|
|
|
740
795
|
## Development
|
data/lib/inquirex/version.rb
CHANGED