Update Contact Tool
The update_contact tool lets the plan executor update contact profile fields during execution. Unlike send_email and send_sms, it executes immediately without approval — the executor writes field changes directly to the database.
Action Gating
Section titled “Action Gating”The tool is only available when the Update Contact action is assigned to the plan template. Without it, the executor cannot see or call the tool.
-- Seeded action recordINSERT INTO "action" (id, name, required_tools)VALUES ('a0000000-0000-0000-0000-000000000004', 'Update Contact', '["update_contact"]');When you add this action to a template, its prompt_fragment is injected into the executor’s system prompt, instructing the LLM to use the tool directly whenever it learns new information about a contact.
Supported Fields
Section titled “Supported Fields”The tool accepts any combination of these optional fields. Omitted fields remain unchanged.
| Field | Type | Validation |
|---|---|---|
contact_id | String (UUID) | Required. Must belong to the plan. |
first_name | String | — |
last_name | String | — |
company | String | — |
job_title | String | — |
timezone | String | IANA timezone (e.g. America/New_York). Validated against chrono_tz. |
preferred_language | String | — |
gender | String | male, female, non-binary |
pipeline_stage | String | lead, prospect, qualified, customer, churned |
date_of_birth | String | ISO 8601 date (e.g. 1990-05-15). Validated against NaiveDate. |
source | String | — |
Execution Flow
Section titled “Execution Flow”LLM calls update_contact({ contact_id, company: "Acme Inc", pipeline_stage: "qualified" }) → Parse UUID → Guard: contact must be in this plan's contact list → Build ContactFieldUpdates with only provided fields → Validate timezone (chrono_tz) and date_of_birth (NaiveDate) → Write to database (selective UPDATE, only non-None fields) → Log UpdateContact entry with field→value changes → Return: "Contact updated: company → Acme Inc, pipeline stage → qualified"The tool only updates fields you provide — it never clears existing values.
Service Layer
Section titled “Service Layer”The update logic lives in update_contact_fields_service.rs:
pub struct ContactFieldUpdates { pub first_name: Option<String>, pub last_name: Option<String>, pub company: Option<String>, pub job_title: Option<String>, pub timezone: Option<String>, pub preferred_language: Option<String>, pub gender: Option<String>, pub pipeline_stage: Option<String>, pub date_of_birth: Option<String>, pub source: Option<String>, pub external_id: Option<String>,}
pub async fn update_contact_fields( contact_id: Uuid, organization_id: Uuid, fields: ContactFieldUpdates,) -> Result<Vec<String>, AppError>Returns a Vec<String> of human-readable change descriptions (e.g. "company → Acme Inc").
Log Entry Types
Section titled “Log Entry Types”Updates are logged in the plan timeline with structured input/output:
pub struct UpdateContactInput { pub contact_id: Uuid, pub fields: HashMap<String, String>,}
pub struct UpdateContactOutput { pub changes: Vec<String>,}The entry uses ToolCallRole::PostAction — it attaches to the previous primary node (like send_email) in the graph view rather than appearing as a standalone node.
UI Rendering
Section titled “UI Rendering”Update contact entries appear in both the timeline and graph views:
- Icon:
UserPen(lucide) - Color: Emerald — same as
write_interaction_noteandupdate_system_note - Label: “Update Contact”
- Detail: Lists each field change as
"field name → new value"
Error Handling
Section titled “Error Handling”| Error | Response |
|---|---|
| Invalid UUID | "Invalid contact_id UUID: {error}" |
| Contact not in plan | "Contact not associated with this plan" |
| Invalid timezone | AppError::InvalidInput — bad IANA timezone string |
| Invalid date | AppError::InvalidInput — bad ISO 8601 date string |
Key Files
Section titled “Key Files”| File | Purpose |
|---|---|
migration/src/m20260324_120001_seed_update_contact_action.rs | Seeds the action record |
src/mods/contact/services/update_contact_fields_service.rs | Field update logic + validation |
src/mods/plan/types/plan_tool_type.rs | PlanTool::UpdateContact enum variant |
src/mods/plan/tools/build_tools.rs | Tool schema + execution handler |
src/mods/plan/types/plan_log_entry_type.rs | Log entry types + PostAction role |