Appearance
AutoOps Pre-Call Prefetch
Status: planned (2026-06-16). Plan:
.indusk/planning/autoops-precall-prefetch/(research → brief → test-plan → ADR all accepted; impl in progress). Blueprint-team dev Tiger Ma confirmed the pre-call approach. This page is authored before code (doc-before-build) and is refined as phases land.
Problem
The availability-first prompt wants the agent to open a call already knowing who is calling and to lead with a real appointment time. Today every call pays for that in-call: it round-trips autoOpsLookupCustomerContext to identify the caller, then autoOpsGetAvailability to find a slot, before it can confirm the vehicle or offer a time. That is latency and dead air at exactly the moment we want the agent to feel fast and businesslike. The pre-call pipeline already runs before the agent speaks and already holds the caller's phone number, so that work can move up front.
Current sequence
Two in-call round-trips happen while the caller waits.
Proposed sequence
The agent opens already holding the caller's context and the oil-change times. The in-call tools stay registered and are used as fallback (unmatched caller, stale data, any service other than oil change).
How it works
- Gate. An AutoOps branch in
getPrecallCRMInfo, entered whengetAutoOpsConfig(teamId).enabledis true. NottypedConfig.crm— AutoOps has no crm-enum value. - Call pattern. Customer lookup and both oil-change availability calls (drop-off + waiter) run in one
Promise.all, so total latency is roughly the slowest single call, inside the 3sPRE_CALL_CRM_TIMEOUT_MSbudget. - Fail-open. The prefetch inherits the pipeline's timeout + error wrapper. A slow or failing prefetch returns no variables and never blocks or delays pickup; the agent falls back to the in-call tools.
- Injection. Results flow through the existing
variableValuespath (message→{{crmInfo}},structured→ flattened named variables), delivered to the ElevenLabs agent (the default platform) as dynamic variables in the conversation-initiation response. - Additive. No tool registration or
agent-factorychanges; "use the injected value and skip the lookup" is a prompt instruction, not a wiring change.
What's injected
Both halves are folded into the single injected {{crmInfo}} block (the same channel as the existing CRM branches), not separate named variables:
| Group | Content | Source |
|---|---|---|
| Customer context | name, vehicle(s) on file, upcoming appointments, returning-vs-new | lookupCustomer + getVehiclesPage + getJobsPage |
| Availability (oil change) | earliest drop-off and earliest waiter time | getServices (name match) + two getAvailability calls |
Availability is seeded for oil change only — the caller's actual service is unknown pre-call, so any other service still uses the in-call availability call. Availability is shop-level, so it seeds even for a first-time caller with no record. An availability error drops only that lane; the customer context still injects.
Telemetry
A precall.autoops span tree is the single source for observability:
- parent span with total duration (compared against the 3s budget),
customer_found, and per-slotseededflags; - child spans per AutoOps call (lookup, vehicles, jobs, drop-off availability, waiter availability) with latency and outcome;
- failures recorded with
recordException+setStatus(ERROR)+ a trace-correlated log; the fail-open path setsprecall.autoops.miss+miss_reason(error vs timeout).
This gives prefetch hit-rate, miss-rate + cause, and the latency distribution (the p50/p95) without a separate measurement harness. A follow-up signal confirms the in-call tool-call count actually drops for known callers — the prefetch is only valuable if it does.
See also
- ADR:
.indusk/planning/autoops-precall-prefetch/adr.md - The prompt side that consumes these variables: the EAS-blueprint rework (
.indusk/sandbox/prompts/EAS-blueprint/).