When May Botie Turn a Suggestion into an Action?
Booking an inspection changes somebody’s work. Give the tool a precise interface, check the caller’s permission, and keep a retried request from creating a second job.
15 sections · 4 questions · 1 coding challenge
The arrow keys move between sections too.
A Missing Response Does Not Mean a Missing Action
BOTIE
ReAct studied language-model interactions that interleave reasoning and actions, allowing observations to affect subsequent steps. Once a proposed action reaches a real service, ordinary service guarantees still matter. Our workshop separates a model’s candidate request from the application checks that decide whether it can proceed.
Sources for this history
One Proposed Inspection Becomes Two Appointments
A technician approves an inspection for P-2. Botie sends the request, but the connection drops before the response arrives. Did the service create the appointment? Sending the request again might repair the missing response, or it might book the same inspection twice.
We need to define what a tool call means before wiring it into an agent. Its inputs need validation, the caller needs permission, and retries need a way to refer to the same intended action.
This offline decision table performs no scheduling and stores no real appointments.
Step 1 of 2
Read the request and its receipt together
A retry needs an identity for the intended action, not a guess based on similar text.
| Situation | Current request | Stored request for that ID | Decision |
|---|---|---|---|
| First attempt | r7: P-2, 20 minutes | None | create |
| Response was lost | r7: P-2, 20 minutes | r7: P-2, 20 minutes | reuse |
| Same ID, changed action | r7: P-2, 35 minutes | r7: P-2, 20 minutes | conflict |
First attempt
- Current request
- r7: P-2, 20 minutes
- Stored request for that ID
- None
- Decision
- create
Response was lost
- Current request
- r7: P-2, 20 minutes
- Stored request for that ID
- r7: P-2, 20 minutes
- Decision
- reuse
Same ID, changed action
- Current request
- r7: P-2, 35 minutes
- Stored request for that ID
- r7: P-2, 20 minutes
- Decision
- conflict
Step 2 of 2
Permission lives in the application
The document or model cannot assign itself more authority.
- 1
Model proposal
asset, minutes, request ID - 2
Server checks
- Schema and authenticated caller scope
- Approval bound to this request
- 3
Idempotency store
Existing receipt or a new atomic creation - 4
Tool result
Success or a structured error
A tool proposal becomes a checked service request
A model proposal does not decide permission or whether a request is new. The decision follows the application’s checked inputs.
Would this request create, reuse, or reject a job?
Change permission, approval, or the previous request stored under the same request ID. Inspect the branch responsible for the decision.
BOTIE
create, reuse, conflict, or deny
create
Follow the operations
1. Already validated inspection proposal
{ "request_id": "r7", "asset": "P-2", "minutes": 20 }2. Read a record field
P-2
3. Authoritative allowed assets
- 0P-2
4. Check membership
true
5. Application approval for this exact request
true
6. Require both checks
true
7. Earlier request stored under this ID
null
8. No earlier record (null)
null
9. Compare complete values
true
10. Text value
create
11. Compare complete values
false
12. Text value
reuse
13. Text value
conflict
14. Choose from a check
conflict
15. Choose from a check
create
16. Text value
deny
17. Choose from a check
create
18. Result
create
This circuit returns a decision label only. Production execution requires bound approval and atomic, durable idempotency storage.
1. A tool is a callable operation with a contract
A model does not execute an inspection by writing its name. It proposes a call, usually a tool name and structured arguments. Application code validates the proposal and invokes a specific implementation. The tool result returns as another observation for the model.
For this service, propose_inspection has an asset ID, duration in minutes, and request ID. Its description must explain units and whether it only drafts a request or actually reserves a technician. Those effects are part of the interface. A vague tool named do_task makes it hard for both the model and the programmer to know what will happen.
Prefer operations with understandable effects. Reading a manual and creating an appointment need different permissions and failure handling.
2. Validate arguments before looking up permissions
An asset is nonempty text, duration is a whole number from 1 through 60, and request ID is nonempty text in this teaching contract. Extra fields are rejected. An input named admin cannot grant administrator access merely because the model supplied it.
Schema validation catches malformed input. Business rules add further constraints: the asset must exist, the maintenance window must be available, and the intended action must be allowed for the authenticated user. These checks belong in the service even if an earlier framework has already checked the tool-call format.
In Python, bool is a subclass of int. A strict whole-minute check should reject True rather than accidentally treating it as one minute.
Inspect a strict duration check
The program checks a few values without creating a request. type(value) is int deliberately excludes booleans.
def valid_minutes(value):
return type(value) is int and 1 <= value <= 60
for value in [20, True, 0, 2.5]:
print(valid_minutes(value))True
False
False
FalseThe allowed range is an invented service rule, not a general limit on inspections.
3. Get permission from the authenticated request
The server knows which user is signed in and which assets that user may schedule. That scope is different from a model-generated claim that the user is authorised. Look up or derive the scope from trusted application state, then check the requested asset against it.
A technician may be allowed to read one site’s manuals and book only their own site’s inspections. Scope can apply to an organisation, a resource and an operation. Apply the checks at execution time, since permissions may have changed since the conversation began.
The workshop supplies an authoritative allowed-asset list. A real service must produce that list from authentication and authorisation rules, not from the model’s answer.
4. Bind approval to the action being approved
For an action that needs human approval, show the actual asset and proposed duration. Record approval for that exact payload and actor. If the model later changes the duration or selects a different asset, the old approval must not silently authorise the new request.
Our approved flag represents a check already performed by the application. It is not a field the model gets to set. An approval screen is useful only if the execution path verifies that the approved request still matches the request it is about to perform.
A tool description can remind a model to ask, but server-side checks determine whether a side effect is allowed.
Check yourself
Questions on Parts 1 to 4
Question 1 of 2
Which authority decides whether P-2 may be scheduled?
Use the information below.
A proposed call contains asset P-2 and admin=true. The authenticated caller is permitted only for P-1.5. Use a stable key for the same intended action
A request ID identifies the same intended action across retries. If r7 already created an inspection, a later r7 with the same payload should return the previous result. If r7 arrives with a different payload, report a conflict instead of guessing which action the caller intended.
This is different from deduplicating every identical-looking inspection forever. Two legitimate inspections can have the same asset and duration but different request IDs. The service needs a documented key scope and retention period. In production, the key should be scoped to the authenticated caller or tenant as appropriate.
A retry should retain its original ID. Creating a fresh ID for every network attempt defeats the deduplication contract.
6. Make the receipt and the side effect agree
A simple “check whether the key exists, then create” can race. Two workers may both see no key and both create a job. The real service needs an atomic operation, uniqueness constraint, transaction or equivalent protocol that makes only one creation succeed.
It must also address a crash between creating the job and saving the receipt. The details depend on the storage and downstream service. Our Python function decides which branch a supplied state should take; it deliberately does not claim to solve distributed transactions.
Idempotency requires durable service behaviour. A prompt asking the model not to repeat itself cannot provide that guarantee.
7. Return a result that supports the next decision
A successful tool result should identify the job or reused receipt. A denied request should say it was denied without exposing another user’s private records. A validation error can identify repairable fields. A conflict should preserve the old action and require a deliberate resolution.
Do not turn an arbitrary tool error into an encouraging sentence that implies success. The next agent step needs to distinguish an observation from a failure to obtain one. Retry only error classes for which retry is appropriate, within a limit.
Botie’s workshop checks permission first, then chooses create, reuse or conflict. This ordering also avoids revealing stored receipt details to a caller who is no longer permitted.
8. Keep the teaching boundary visible
The workshop request is already schema-validated. You will construct permission and idempotency decisions from smaller checks. The Python challenge adds argument validation so malformed proposals do not reach those decisions. Both use invented in-memory records.
When connecting a live tool, carry over the separation rather than copying this in-memory example as a production booking service. Authentication, approval binding, atomic storage, audit records and a documented recovery path still need real implementations.
The next lesson returns to reading information. Read-only tools have fewer side effects, but their context still needs permission checks and a useful size limit.
Check yourself
Questions on Parts 1 to 8
Question 1 of 2
What should this contract do?
Use the information below.
Request r7 previously created a P-2 inspection lasting 20 minutes. A retry uses r7 for 35 minutes.Try it with Botie
Build with Botie
Write and run Python