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.
@@ -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
+ }