- An AI agent reads natural-language availability and translates it into structured data
- A constraint solver takes that structured data and finds a time slot that satisfies everyone — or reports that no such time exists
Why Two Systems?
AI agents are great at understanding language. If someone says “mornings before noon,” an agent can figure out that means 9am–12pm on business days. But agents aren’t reliable at combinatorial search — finding the intersection of four people’s overlapping windows across five days and eight hours. They might get it right, but they might not, and you’d have no way to be sure. Constraint solvers work the other way around. They’re designed to search through combinations exhaustively and either find a valid solution or prove that none exists. But they need precise, structured input — they can’t read “I’m free Tuesday afternoons.” By combining both, you get the best of each: the agent handles language understanding, and the solver handles the search. The answer is guaranteed to be correct if the agent parsed the availability correctly.The Data Types
First, define the structured types that bridge the two systems. These use Thinkwell’s@JSONSchema annotation so the AI agent’s output is automatically validated against them.
A TimeWindow represents a single block of availability:
ParsedConstraints collects each attendee’s windows into a single structure:
ScheduleResult for the final human-friendly output:
@minimum and @maximum JSDoc tags on TimeWindow add numeric constraints to the schema. This helps the agent stay within valid ranges — hours should be between 0 and 24, not arbitrary numbers.
Step 1: Parse Availability with the Agent
Load the attendee data and ask the agent to translate each person’s natural-language availability into structuredTimeWindow objects:
ParsedConstraints.Schema ensures the output matches the expected shape exactly.
For example, Alice’s “Free Monday, Wednesday, and Friday mornings before noon” becomes:
Step 2: Find a Valid Time with the Solver
Now comes the part where a solver really shines. We need to find a single(day, hour) pair that falls within at least one availability window for every attendee. With four people and multiple windows each, there are a lot of combinations to check.
The z3-solver npm package lets you describe what a valid answer looks like, and it searches for one automatically:
dayandhourare variables — the solver will figure out their valuessolver.add(...)tells the solver what has to be true: the day must be a weekday (0–4), the hour must be within business hours (9–17), and each attendee’s windows must include the chosen timesolver.check()does the actual search — if it returns"sat"(satisfiable), a valid time exists and we can read it from the model
Step 3: Summarize the Result
Finally, ask the agent to produce a friendly summary:The Full Script
Here’s everything together:Running the Example
Key Takeaways
- Use AI for language, solvers for search. The agent is great at understanding what “mornings before noon” means. The solver is great at finding the intersection of everyone’s availability. Neither is great at the other’s job.
-
Structured types are the bridge. The
@JSONSchematypes define a clear contract between the two systems. The agent fills in the structure; the solver reads it. - Guaranteed correctness where it matters. The solver doesn’t guess — it either finds a valid time or proves none exists. This is a stronger guarantee than asking an agent to “figure out when everyone is free.”
- The pattern generalizes. Any problem where you need to understand fuzzy human input and then find an exact answer is a good fit for this approach: resource allocation, timetabling, configuration, logistics, and more.
