inquirex-tty 0.4.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 +7 -0
- data/.envrc +3 -0
- data/.relaxed_rubocop.yml +153 -0
- data/.secrets.baseline +127 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +530 -0
- data/Rakefile +36 -0
- data/docs/badges/coverage_badge.svg +21 -0
- data/examples/01_hello_world.rb +32 -0
- data/examples/02_yes_or_no.rb +33 -0
- data/examples/03_food_preferences.png +0 -0
- data/examples/03_food_preferences.rb +65 -0
- data/examples/04_event_registration.rb +86 -0
- data/examples/05_job_application.rb +122 -0
- data/examples/06_health_assessment.rb +173 -0
- data/examples/07_loan_application.rb +217 -0
- data/examples/08_tax_preparer.rb +195 -0
- data/examples/09_tax_preparer_llm.rb +151 -0
- data/examples/10_answers.json +53 -0
- data/examples/10_real_tax_preparer.rb +604 -0
- data/examples/README.md +50 -0
- data/exe/inquirex +24 -0
- data/justfile +56 -0
- data/lefthook.yml +36 -0
- data/lib/inquirex/tty/commands/export.rb +81 -0
- data/lib/inquirex/tty/commands/graph.rb +116 -0
- data/lib/inquirex/tty/commands/run.rb +193 -0
- data/lib/inquirex/tty/commands/validate.rb +108 -0
- data/lib/inquirex/tty/commands/version.rb +19 -0
- data/lib/inquirex/tty/commands.rb +19 -0
- data/lib/inquirex/tty/flow_loader.rb +41 -0
- data/lib/inquirex/tty/output_path.rb +66 -0
- data/lib/inquirex/tty/renderer.rb +245 -0
- data/lib/inquirex/tty/ui_helper.rb +58 -0
- data/lib/inquirex/tty/version.rb +7 -0
- data/lib/inquirex/tty.rb +41 -0
- data/sig/inquirex/tty.rbs +6 -0
- metadata +197 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Example 8: Tax Preparer Intake
|
|
4
|
+
#
|
|
5
|
+
# The most complex example — 18+ steps with multi-level branching,
|
|
6
|
+
# enum selections, boolean gates, and free-text collection.
|
|
7
|
+
# Demonstrates a real-world intake wizard for a tax preparation service.
|
|
8
|
+
#
|
|
9
|
+
# Note: The original flowengine example used number_matrix for collecting
|
|
10
|
+
# structured numeric data (business types, rental property counts). Inquirex
|
|
11
|
+
# uses :string steps for those sections since number_matrix is not part of
|
|
12
|
+
# the Inquirex DSL. All rule logic is preserved.
|
|
13
|
+
#
|
|
14
|
+
# Run: bundle exec exe/inquirex-tty run examples/08_tax_preparer.rb
|
|
15
|
+
|
|
16
|
+
Inquirex.define id: "tax-preparer-2025", version: "1.0.0" do
|
|
17
|
+
meta title: "Tax Preparation Intake",
|
|
18
|
+
subtitle: "Help us understand your tax situation"
|
|
19
|
+
|
|
20
|
+
start :intro
|
|
21
|
+
|
|
22
|
+
# Opening instructions (no input collected)
|
|
23
|
+
say :intro do
|
|
24
|
+
text "Please describe your tax situation in a few sentences.\n" \
|
|
25
|
+
"Do not under any circumstances provide personal information,\n" \
|
|
26
|
+
"such as your address or social security number.\n\n" \
|
|
27
|
+
"Example: I have two W-2s from my two jobs, a rental property, " \
|
|
28
|
+
"and a side business."
|
|
29
|
+
transition to: :filing_status
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
ask :filing_status do
|
|
33
|
+
type :enum
|
|
34
|
+
question "What is your filing status for 2025?"
|
|
35
|
+
options({
|
|
36
|
+
"single" => "Single",
|
|
37
|
+
"married_filing_jointly" => "Married Filing Jointly",
|
|
38
|
+
"married_filing_separately" => "Married Filing Separately",
|
|
39
|
+
"head_of_household" => "Head of Household",
|
|
40
|
+
"widowed" => "Widowed"
|
|
41
|
+
})
|
|
42
|
+
widget target: :tty, type: :select
|
|
43
|
+
widget target: :desktop, type: :radio_group, columns: 1
|
|
44
|
+
widget target: :mobile, type: :dropdown
|
|
45
|
+
transition to: :dependents
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
ask :dependents do
|
|
49
|
+
type :integer
|
|
50
|
+
question "How many dependents do you have?"
|
|
51
|
+
widget target: :tty, type: :number_input
|
|
52
|
+
default 0
|
|
53
|
+
transition to: :income_types
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
ask :income_types do
|
|
57
|
+
type :multi_enum
|
|
58
|
+
question "Select all income types that apply to you in 2025."
|
|
59
|
+
options %w[W2 1099 Business Investment Rental Retirement]
|
|
60
|
+
widget target: :tty, type: :multi_select
|
|
61
|
+
widget target: :desktop, type: :checkbox_group
|
|
62
|
+
transition to: :business_count, if_rule: contains(:income_types, "Business")
|
|
63
|
+
transition to: :investment_details, if_rule: contains(:income_types, "Investment")
|
|
64
|
+
transition to: :rental_details, if_rule: contains(:income_types, "Rental")
|
|
65
|
+
transition to: :state_filing
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
ask :business_count do
|
|
69
|
+
type :integer
|
|
70
|
+
question "How many total businesses do you own or are a partner in?"
|
|
71
|
+
widget target: :tty, type: :number_input
|
|
72
|
+
transition to: :complex_business_info, if_rule: greater_than(:business_count, 2)
|
|
73
|
+
transition to: :business_details
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
ask :complex_business_info do
|
|
77
|
+
type :text
|
|
78
|
+
question "With more than 2 businesses, please provide your primary EIN " \
|
|
79
|
+
"and a brief description of each entity."
|
|
80
|
+
widget target: :tty, type: :multiline
|
|
81
|
+
transition to: :business_details
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Collect counts for each business type (RealEstate, SCorp, CCorp, Trust, LLC)
|
|
85
|
+
ask :business_details do
|
|
86
|
+
type :string
|
|
87
|
+
question "How many of each business type do you own? " \
|
|
88
|
+
"(RealEstate, SCorp, CCorp, Trust, LLC — enter comma-separated counts)"
|
|
89
|
+
widget target: :tty, type: :text_input
|
|
90
|
+
transition to: :investment_details, if_rule: contains(:income_types, "Investment")
|
|
91
|
+
transition to: :rental_details, if_rule: contains(:income_types, "Rental")
|
|
92
|
+
transition to: :state_filing
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
ask :investment_details do
|
|
96
|
+
type :multi_enum
|
|
97
|
+
question "What types of investments do you hold?"
|
|
98
|
+
options %w[Stocks Bonds Crypto RealEstate MutualFunds]
|
|
99
|
+
widget target: :tty, type: :multi_select
|
|
100
|
+
widget target: :desktop, type: :checkbox_group
|
|
101
|
+
transition to: :crypto_details, if_rule: contains(:investment_details, "Crypto")
|
|
102
|
+
transition to: :rental_details, if_rule: contains(:income_types, "Rental")
|
|
103
|
+
transition to: :state_filing
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
ask :crypto_details do
|
|
107
|
+
type :text
|
|
108
|
+
question "Please describe your cryptocurrency transactions " \
|
|
109
|
+
"(exchanges used, approximate number of transactions)."
|
|
110
|
+
widget target: :tty, type: :multiline
|
|
111
|
+
transition to: :rental_details, if_rule: contains(:income_types, "Rental")
|
|
112
|
+
transition to: :state_filing
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Collect counts for each rental property type (Residential, Commercial, Vacation)
|
|
116
|
+
ask :rental_details do
|
|
117
|
+
type :string
|
|
118
|
+
question "How many rental properties of each type do you own? " \
|
|
119
|
+
"(Residential, Commercial, Vacation — enter comma-separated counts)"
|
|
120
|
+
widget target: :tty, type: :text_input
|
|
121
|
+
transition to: :state_filing
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
ask :state_filing do
|
|
125
|
+
type :multi_enum
|
|
126
|
+
question "Which states do you need to file in?"
|
|
127
|
+
options %w[California NewYork Texas Florida Illinois Other]
|
|
128
|
+
widget target: :tty, type: :multi_select
|
|
129
|
+
widget target: :desktop, type: :checkbox_group
|
|
130
|
+
transition to: :foreign_accounts
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
ask :foreign_accounts do
|
|
134
|
+
type :enum
|
|
135
|
+
question "Do you have any foreign financial accounts " \
|
|
136
|
+
"(bank accounts, securities, or financial assets)?"
|
|
137
|
+
options %w[yes no]
|
|
138
|
+
widget target: :tty, type: :select
|
|
139
|
+
widget target: :desktop, type: :radio_group
|
|
140
|
+
transition to: :foreign_account_details, if_rule: equals(:foreign_accounts, "yes")
|
|
141
|
+
transition to: :deduction_types
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
ask :foreign_account_details do
|
|
145
|
+
type :integer
|
|
146
|
+
question "How many foreign accounts do you have?"
|
|
147
|
+
widget target: :tty, type: :number_input
|
|
148
|
+
transition to: :deduction_types
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
ask :deduction_types do
|
|
152
|
+
type :multi_enum
|
|
153
|
+
question "Which additional deductions apply to you?"
|
|
154
|
+
options %w[Medical Charitable Education Mortgage None]
|
|
155
|
+
widget target: :tty, type: :multi_select
|
|
156
|
+
widget target: :desktop, type: :checkbox_group
|
|
157
|
+
transition to: :charitable_amount, if_rule: contains(:deduction_types, "Charitable")
|
|
158
|
+
transition to: :client_name
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
ask :charitable_amount do
|
|
162
|
+
type :currency
|
|
163
|
+
question "How much did you donate to charity in 2025?"
|
|
164
|
+
widget target: :tty, type: :number_input
|
|
165
|
+
transition to: :charitable_documentation, if_rule: greater_than(:charitable_amount, 5000)
|
|
166
|
+
transition to: :client_name
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
ask :charitable_documentation do
|
|
170
|
+
type :text
|
|
171
|
+
question "For charitable contributions over $5,000, please describe " \
|
|
172
|
+
"what sort of paperwork you have available."
|
|
173
|
+
widget target: :tty, type: :multiline
|
|
174
|
+
transition to: :client_name
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
ask :client_name do
|
|
178
|
+
type :string
|
|
179
|
+
question "Your name, please:"
|
|
180
|
+
widget target: :tty, type: :text_input
|
|
181
|
+
transition to: :client_email
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
ask :client_email do
|
|
185
|
+
type :email
|
|
186
|
+
question "Your email address:"
|
|
187
|
+
widget target: :tty, type: :text_input
|
|
188
|
+
transition to: :thanks
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
say :thanks do
|
|
192
|
+
text "Thank you! We will review your information and send you " \
|
|
193
|
+
"a tax preparation estimate within 1-2 business days."
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Example 09: Tax Preparer Intake with LLM-assisted pre-fill
|
|
4
|
+
#
|
|
5
|
+
# The thesis:
|
|
6
|
+
# "Deterministic DSL defines what data you need.
|
|
7
|
+
# LLM extracts what it can from one free-text answer.
|
|
8
|
+
# The engine only asks what's left."
|
|
9
|
+
#
|
|
10
|
+
# Flow:
|
|
11
|
+
# 1. :describe — one open-ended question
|
|
12
|
+
# 2. :extracted — clarify step; LLM returns structured fields
|
|
13
|
+
# 3. :filing_status, :dependents, :income_types, :state_filing, :client_contact
|
|
14
|
+
# — asked only when the LLM left the field blank
|
|
15
|
+
# 4. :summary — LLM produces a complexity / fee summary over everything
|
|
16
|
+
# 5. :done — farewell
|
|
17
|
+
#
|
|
18
|
+
# Run:
|
|
19
|
+
# bundle exec exe/inquirex-tty run examples/09_tax_preparer_llm.rb
|
|
20
|
+
#
|
|
21
|
+
# Uses ANTHROPIC_API_KEY from .env (or any parent .env) for live Claude calls.
|
|
22
|
+
# Falls back to Inquirex::LLM::NullAdapter when the key is absent, or when
|
|
23
|
+
# INQUIREX_LLM_ADAPTER=null is set.
|
|
24
|
+
|
|
25
|
+
require "inquirex"
|
|
26
|
+
require "inquirex/llm"
|
|
27
|
+
|
|
28
|
+
Inquirex.define id: "tax-preparer-llm-2025", version: "1.0.0" do
|
|
29
|
+
meta title: "Tax Prep Intake (LLM-assisted)",
|
|
30
|
+
subtitle: "Tell us about your tax situation — we'll only ask what we can't figure out"
|
|
31
|
+
|
|
32
|
+
start :describe
|
|
33
|
+
|
|
34
|
+
ask :describe do
|
|
35
|
+
type :text
|
|
36
|
+
question "Please describe your 2025 tax situation in your own words.\n" \
|
|
37
|
+
"Mention filing status, kids/dependents, income sources\n" \
|
|
38
|
+
"(W-2, business, rental, investments, crypto), and your state.\n" \
|
|
39
|
+
"Do NOT include SSN or home address."
|
|
40
|
+
widget target: :tty, type: :multiline
|
|
41
|
+
transition to: :extracted
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
clarify :extracted do
|
|
45
|
+
from :describe
|
|
46
|
+
prompt <<~PROMPT
|
|
47
|
+
You are a tax-prep intake assistant. Extract structured information from
|
|
48
|
+
the client's free-text description.
|
|
49
|
+
|
|
50
|
+
STRICT VALUE RULES — you MUST use these exact string literals, no others:
|
|
51
|
+
|
|
52
|
+
filing_status: exactly ONE of:
|
|
53
|
+
"single" | "married_filing_jointly" | "married_filing_separately"
|
|
54
|
+
| "head_of_household" | "widowed"
|
|
55
|
+
Use "" (empty string) if the client did not indicate a filing status.
|
|
56
|
+
|
|
57
|
+
dependents: integer count of dependents (0 if client said they have none;
|
|
58
|
+
null only if the client made no mention of dependents at all).
|
|
59
|
+
|
|
60
|
+
income_types: array. Each element MUST be ONE of these exact tokens
|
|
61
|
+
(case-sensitive, no hyphens, no spaces, no variants):
|
|
62
|
+
"W2" — W-2 employment / regular salary / wage job
|
|
63
|
+
"1099" — 1099 contracting / freelance / gig work
|
|
64
|
+
"Business" — self-employment, LLC, S-corp, C-corp, sole-prop, partnership, consulting business
|
|
65
|
+
"Investment" — stocks, bonds, crypto, mutual funds, dividends, capital gains
|
|
66
|
+
"Rental" — rental property income (residential, commercial, or vacation)
|
|
67
|
+
"Retirement" — 401(k), IRA, pension, social-security income
|
|
68
|
+
Do NOT output "W-2", "self-employment", "self_employment", "rental income",
|
|
69
|
+
"investments", or any variant — use only the tokens listed above.
|
|
70
|
+
Use [] if the client mentioned no income types.
|
|
71
|
+
|
|
72
|
+
state_filing: the primary US state as a capitalized English name
|
|
73
|
+
("California", "New York", "Texas"). Use "" if unmentioned.
|
|
74
|
+
|
|
75
|
+
IMPORTANT: Only include a value when the client's text gives you concrete
|
|
76
|
+
evidence. Do NOT infer or guess. Use null / "" / [] liberally.
|
|
77
|
+
PROMPT
|
|
78
|
+
schema filing_status: :string,
|
|
79
|
+
dependents: :integer,
|
|
80
|
+
income_types: :multi_enum,
|
|
81
|
+
state_filing: :string
|
|
82
|
+
model :claude_sonnet
|
|
83
|
+
temperature 0.0
|
|
84
|
+
transition to: :filing_status
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
ask :filing_status do
|
|
88
|
+
type :enum
|
|
89
|
+
question "What is your filing status for 2025?"
|
|
90
|
+
options({
|
|
91
|
+
"single" => "Single",
|
|
92
|
+
"married_filing_jointly" => "Married Filing Jointly",
|
|
93
|
+
"married_filing_separately" => "Married Filing Separately",
|
|
94
|
+
"head_of_household" => "Head of Household",
|
|
95
|
+
"widowed" => "Widowed"
|
|
96
|
+
})
|
|
97
|
+
widget target: :tty, type: :select
|
|
98
|
+
skip_if not_empty(:filing_status)
|
|
99
|
+
transition to: :dependents
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
ask :dependents do
|
|
103
|
+
type :integer
|
|
104
|
+
question "How many dependents do you have?"
|
|
105
|
+
widget target: :tty, type: :number_input
|
|
106
|
+
default 0
|
|
107
|
+
skip_if not_empty(:dependents)
|
|
108
|
+
transition to: :income_types
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
ask :income_types do
|
|
112
|
+
type :multi_enum
|
|
113
|
+
question "Select all income types that apply to you in 2025."
|
|
114
|
+
options %w[W2 1099 Business Investment Rental Retirement]
|
|
115
|
+
widget target: :tty, type: :multi_select
|
|
116
|
+
skip_if not_empty(:income_types)
|
|
117
|
+
transition to: :state_filing
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
ask :state_filing do
|
|
121
|
+
type :string
|
|
122
|
+
question "Which state do you need to file in?"
|
|
123
|
+
widget target: :tty, type: :text_input
|
|
124
|
+
skip_if not_empty(:state_filing)
|
|
125
|
+
transition to: :client_contact
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
ask :client_contact do
|
|
129
|
+
type :string
|
|
130
|
+
question "Your name and email (so we can send the quote)?"
|
|
131
|
+
widget target: :tty, type: :text_input
|
|
132
|
+
transition to: :summary
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
summarize :summary do
|
|
136
|
+
from_all
|
|
137
|
+
prompt <<~PROMPT
|
|
138
|
+
Based on the collected answers, produce a concise JSON object with:
|
|
139
|
+
- complexity: "simple" | "moderate" | "complex"
|
|
140
|
+
- fee_estimate_low: integer USD
|
|
141
|
+
- fee_estimate_high: integer USD
|
|
142
|
+
- red_flags: array of short strings (empty array if none)
|
|
143
|
+
- notes: one-sentence summary for the preparer
|
|
144
|
+
PROMPT
|
|
145
|
+
transition to: :done
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
say :done do
|
|
149
|
+
text "Thank you! A tax professional will review your intake and reach out."
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"flow_file": "examples/10_real_tax_preparer.rb",
|
|
3
|
+
"path_taken": [
|
|
4
|
+
"intro",
|
|
5
|
+
"residency_status",
|
|
6
|
+
"prior_return_available",
|
|
7
|
+
"filing_status",
|
|
8
|
+
"dependents_band",
|
|
9
|
+
"income_types",
|
|
10
|
+
"w2_count",
|
|
11
|
+
"state_filing",
|
|
12
|
+
"state_residency",
|
|
13
|
+
"foreign_accounts",
|
|
14
|
+
"surprise_heads_up",
|
|
15
|
+
"tax_notices",
|
|
16
|
+
"estimated_payments",
|
|
17
|
+
"deduction_types",
|
|
18
|
+
"timeline",
|
|
19
|
+
"client_email",
|
|
20
|
+
"thanks"
|
|
21
|
+
],
|
|
22
|
+
"answers": {
|
|
23
|
+
"residency_status": "us_person",
|
|
24
|
+
"prior_return_available": "yes_last_year",
|
|
25
|
+
"filing_status": "married_filing_jointly",
|
|
26
|
+
"dependents_band": "2",
|
|
27
|
+
"income_types": [
|
|
28
|
+
"W2",
|
|
29
|
+
"1099_nec",
|
|
30
|
+
"1099_k"
|
|
31
|
+
],
|
|
32
|
+
"w2_count": "2",
|
|
33
|
+
"state_filing": [
|
|
34
|
+
"CA",
|
|
35
|
+
"CO"
|
|
36
|
+
],
|
|
37
|
+
"state_residency": "multi",
|
|
38
|
+
"foreign_accounts": "no",
|
|
39
|
+
"tax_notices": [
|
|
40
|
+
"state_notice"
|
|
41
|
+
],
|
|
42
|
+
"estimated_payments": "none",
|
|
43
|
+
"deduction_types": [
|
|
44
|
+
"mortgage",
|
|
45
|
+
"salt",
|
|
46
|
+
"hsa_fsa"
|
|
47
|
+
],
|
|
48
|
+
"timeline": "asap",
|
|
49
|
+
"client_email": "kigster@gmail.com"
|
|
50
|
+
},
|
|
51
|
+
"steps_completed": 17,
|
|
52
|
+
"completed_at": "2026-04-14T16:08:16-07:00"
|
|
53
|
+
}
|