autotouch-cli 0.2.31__tar.gz → 0.2.32__tar.gz
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.
- {autotouch_cli-0.2.31/autotouch_cli.egg-info → autotouch_cli-0.2.32}/PKG-INFO +36 -3
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/autotouch_cli/cli.py +28 -178
- autotouch_cli-0.2.31/docs/research-table/reference/autotouch-cli.md → autotouch_cli-0.2.32/autotouch_cli.egg-info/PKG-INFO +44 -2
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/autotouch_cli.egg-info/SOURCES.txt +2 -0
- autotouch_cli-0.2.32/autotouch_cli.egg-info/top_level.txt +2 -0
- autotouch_cli-0.2.32/autotouch_shared/__init__.py +1 -0
- autotouch_cli-0.2.32/autotouch_shared/provider_registry.py +768 -0
- autotouch_cli-0.2.31/PKG-INFO → autotouch_cli-0.2.32/docs/research-table/reference/autotouch-cli.md +35 -11
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/pyproject.toml +2 -2
- autotouch_cli-0.2.31/autotouch_cli.egg-info/top_level.txt +0 -1
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/autotouch_cli/__init__.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/autotouch_cli.egg-info/dependency_links.txt +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/autotouch_cli.egg-info/entry_points.txt +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/autotouch_cli.egg-info/requires.txt +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/setup.cfg +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_column_prompt_compiler.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_contactout_custom.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_contactout_integration.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_contactout_multi_titles.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_contactout_pipeline.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_contactout_simple.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_contactout_v2_bulk.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_lead_required_fields.py +0 -0
- {autotouch_cli-0.2.31 → autotouch_cli-0.2.32}/tests/test_phone_provider_pipeline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autotouch-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.32
|
|
4
4
|
Summary: Autotouch Smart Table CLI
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -515,8 +515,8 @@ autotouch columns create --table-id <TABLE_ID> --data-file <payload.json>
|
|
|
515
515
|
```
|
|
516
516
|
|
|
517
517
|
Recommendation:
|
|
518
|
-
- For provider-backed
|
|
519
|
-
|
|
518
|
+
- For provider-backed or generated columns, start with `autotouch columns recipe`.
|
|
519
|
+
- Built-in recipe types now include `formatter`, `llm_enrichment`, `email_finder`, `phone_finder`, `lead_finder`, `add_to_crm`, `sync_to_table`, and `add_to_sequence`.
|
|
520
520
|
- Email/phone enrichment does not require creating `add_to_crm` first.
|
|
521
521
|
- `add_to_crm` is an optional, non-billable export action.
|
|
522
522
|
|
|
@@ -781,6 +781,7 @@ Notes:
|
|
|
781
781
|
Add-to-Leads note: `companyDomain` is required; LinkedIn is optional. Each row still needs at least one usable hard identity signal (LinkedIn, email, or phone). Names and location fields are metadata only for this flow. Run is non-billable.
|
|
782
782
|
If `companyDomain` is missing in the table, derive or enrich that domain column first, then rerun `add_to_crm`.
|
|
783
783
|
Queued lifecycle: the CLI/API accepts the run immediately, then the backend hands off `ops -> data_io` for execution.
|
|
784
|
+
Creating `add_to_crm` after upstream email/phone/lead columns already finished does not replay those older updates. In that case, run `add_to_crm` explicitly or rerun the upstream source column.
|
|
784
785
|
|
|
785
786
|
CRM data model expectations (recommended before `add_to_crm`):
|
|
786
787
|
- Lead identity/dedupe expects `company_domain` plus one usable hard identity signal. `linkedin_url` is a strong optional signal, not a requirement.
|
|
@@ -819,6 +820,14 @@ CRM data model expectations (recommended before `add_to_crm`):
|
|
|
819
820
|
Notes:
|
|
820
821
|
- Single-destination mode uses `destinationTableId` + `columnMappings`.
|
|
821
822
|
- Router mode is also supported with `config.routes[]` (top-to-bottom matching, first hit wins, default route catches unmatched rows).
|
|
823
|
+
- Route conditions are evaluated against the parent/source row, not against each list item.
|
|
824
|
+
- `autoRun: "onSourceUpdate"` means dependency-driven runs from source row inserts/updates. Saving the column does not backfill existing rows for `sync_to_table`; use an explicit column run/backfill when needed.
|
|
825
|
+
- List mode uses `syncMode: "list"` with `listSourceColumnId` and optional `listPath` (default `items`) to expand a canonical JSON payload like `{ "items": [...], "reasoning": "..." }`.
|
|
826
|
+
- In list mode:
|
|
827
|
+
- `sourceScope: "item"` maps fields from each `items[]` object.
|
|
828
|
+
- `sourceScope: "row"` maps fields from the parent/source row.
|
|
829
|
+
- Explicit item mappings are still recommended for renamed fields such as `name -> full_name`.
|
|
830
|
+
- Blank placeholder list items are skipped and do not create destination rows.
|
|
822
831
|
|
|
823
832
|
### 8) `add_to_sequence`
|
|
824
833
|
|
|
@@ -844,10 +853,33 @@ Notes:
|
|
|
844
853
|
- `sourceLeadColumn` must be the source column key that stores lead IDs (for example `add_to_leads` or another lead-id column key from `lead_finder` output), not the provider name `add_to_crm`.
|
|
845
854
|
- `sequenceId` is the target sequence workflow ID.
|
|
846
855
|
- The target sequence must already be `ACTIVE` for real enrollment. Table `add_to_sequence` runs and direct `POST /api/sequences/{id}/enroll` share the same activation check.
|
|
856
|
+
- Common tail order after contact rows or lead IDs exist is `email_finder -> add_to_crm -> create/activate sequence -> add_to_sequence`.
|
|
857
|
+
- Creating `add_to_sequence` after lead IDs already exist does not replay those older updates. In that case, run `add_to_sequence` explicitly or rerun the lead-id source column.
|
|
847
858
|
- `add_to_sequence` runs auto-attach `research_context.source_table_id` (and table name when available). Field selection stays implicit so sequence drafts/audience resolve favorites from current starred columns by default.
|
|
848
859
|
- Star/favorite the highest-signal fields so callers can see them quickly in the sidecar during live call workflows.
|
|
849
860
|
- The same favorite set is also the default AI drafting context when explicit `fieldIds` are not provided.
|
|
850
861
|
|
|
862
|
+
## Example pipeline: LLM items -> contacts table -> leads -> sequence
|
|
863
|
+
|
|
864
|
+
Use this when an LLM column returns canonical JSON like `{ "items": [...] }` and each item should become a contact row.
|
|
865
|
+
This is an example pattern, not the default recommendation for all person discovery.
|
|
866
|
+
Use `lead_finder` first when the goal is explicit buyer/lead discovery with clear role targeting at scale.
|
|
867
|
+
Use agent `llm_enrichment` when the workflow needs custom research output, website-discovered contacts, or low-coverage / hard-to-find cases.
|
|
868
|
+
|
|
869
|
+
1. Create the source table and import company rows.
|
|
870
|
+
2. Create the LLM enrichment column that outputs `items[]`.
|
|
871
|
+
3. Create `sync_to_table` in `list` mode:
|
|
872
|
+
- set `listSourceColumnId` to the LLM column ID
|
|
873
|
+
- keep item fields on `sourceScope: "item"`
|
|
874
|
+
- keep parent company metadata on `sourceScope: "row"`
|
|
875
|
+
4. Run or wait for `sync_to_table` so the destination contacts table has rows.
|
|
876
|
+
5. On the destination contacts table, create and run `email_finder`.
|
|
877
|
+
6. Create `add_to_crm` on that same destination contacts table.
|
|
878
|
+
7. If email finder already finished before `add_to_crm` existed, run `add_to_crm` explicitly.
|
|
879
|
+
8. Create the target sequence and set it `ACTIVE`.
|
|
880
|
+
9. Create `add_to_sequence` with `sourceLeadColumn` set to the lead-id column key, usually `add_to_leads`.
|
|
881
|
+
10. If leads already existed before `add_to_sequence` was created, run `add_to_sequence` explicitly.
|
|
882
|
+
|
|
851
883
|
## Common workflow
|
|
852
884
|
|
|
853
885
|
```bash
|
|
@@ -1159,6 +1191,7 @@ Agent expectations:
|
|
|
1159
1191
|
- `column_types` tells you which column types are runnable and which are non-billable transforms (`json_split`, `formatter_formula`).
|
|
1160
1192
|
- `filtering` describes valid scope/filter semantics for estimate/run.
|
|
1161
1193
|
- `automation.auto_run` describes supported auto-run modes + config field names.
|
|
1194
|
+
- `automation.providers` exposes provider-specific setup contracts, save-time backfill behavior, dispatch strategy, and recipe type names for formatter/LLM/finders/action columns.
|
|
1162
1195
|
- `execution_policies.llm.output_contract` describes output behavior by mode:
|
|
1163
1196
|
- `agent` => JSON-oriented structured output
|
|
1164
1197
|
- `basic` => text or JSON (`dataType=json` for structured JSON output)
|
|
@@ -34,6 +34,10 @@ from pathlib import Path
|
|
|
34
34
|
from typing import Any, Dict, List, Optional, Tuple
|
|
35
35
|
|
|
36
36
|
import requests
|
|
37
|
+
from autotouch_shared.provider_registry import (
|
|
38
|
+
get_recipe_contract,
|
|
39
|
+
recipe_types,
|
|
40
|
+
)
|
|
37
41
|
|
|
38
42
|
try:
|
|
39
43
|
from pymongo import MongoClient # type: ignore
|
|
@@ -82,186 +86,24 @@ SETUP_BANNER = r"""
|
|
|
82
86
|
AI CLI SETUP
|
|
83
87
|
"""
|
|
84
88
|
|
|
85
|
-
COLUMN_RECIPE_TYPES =
|
|
86
|
-
"email_finder",
|
|
87
|
-
"phone_finder",
|
|
88
|
-
"lead_finder",
|
|
89
|
-
"llm_enrichment",
|
|
90
|
-
"add_to_crm",
|
|
91
|
-
"sync_to_table",
|
|
92
|
-
"add_to_sequence",
|
|
93
|
-
]
|
|
89
|
+
COLUMN_RECIPE_TYPES = recipe_types()
|
|
94
90
|
|
|
95
|
-
COLUMN_CREATE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
96
|
-
"email_finder": {
|
|
97
|
-
"key": "work_email",
|
|
98
|
-
"label": "Work Email",
|
|
99
|
-
"kind": "enrichment",
|
|
100
|
-
"dataType": "json",
|
|
101
|
-
"origin": "email_finder",
|
|
102
|
-
"autoRun": "never",
|
|
103
|
-
"config": {
|
|
104
|
-
"provider": "smart_email_finder",
|
|
105
|
-
"strategy": "cost_optimized",
|
|
106
|
-
"lookupStrategy": "linkedin",
|
|
107
|
-
"linkedinOnly": True,
|
|
108
|
-
"enableProfileFallback": False,
|
|
109
|
-
"linkedinUrl": "linkedin_url",
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
"phone_finder": {
|
|
113
|
-
"key": "mobile_phone",
|
|
114
|
-
"label": "Mobile Phone",
|
|
115
|
-
"kind": "enrichment",
|
|
116
|
-
"dataType": "json",
|
|
117
|
-
"origin": "phone_finder",
|
|
118
|
-
"autoRun": "never",
|
|
119
|
-
"config": {
|
|
120
|
-
"provider": "smart_phone_finder",
|
|
121
|
-
"firstName": "first_name",
|
|
122
|
-
"lastName": "last_name",
|
|
123
|
-
"company": "company",
|
|
124
|
-
"linkedinUrl": "linkedin_url",
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
"lead_finder": {
|
|
128
|
-
"key": "lead_contacts",
|
|
129
|
-
"label": "Lead Contacts",
|
|
130
|
-
"kind": "enrichment",
|
|
131
|
-
"dataType": "json",
|
|
132
|
-
"origin": "ai",
|
|
133
|
-
"autoRun": "never",
|
|
134
|
-
"config": {
|
|
135
|
-
"provider": "lead_finder",
|
|
136
|
-
"sourceMode": "bulk_companies",
|
|
137
|
-
"companyDomain": "domain",
|
|
138
|
-
"strictness": "flexible_roles",
|
|
139
|
-
"storeAsLeads": True,
|
|
140
|
-
"autoEnrichEmails": True,
|
|
141
|
-
"autoEnrichPhones": False,
|
|
142
|
-
"jobTitles": ["Head of Sales", "VP Sales"],
|
|
143
|
-
"locations": ["United States"],
|
|
144
|
-
"maxResults": 10,
|
|
145
|
-
},
|
|
146
|
-
},
|
|
147
|
-
"llm_enrichment": {
|
|
148
|
-
"key": "company_research",
|
|
149
|
-
"label": "Company Research",
|
|
150
|
-
"kind": "enrichment",
|
|
151
|
-
"dataType": "json",
|
|
152
|
-
"origin": "ai",
|
|
153
|
-
"autoRun": "never",
|
|
154
|
-
"config": {
|
|
155
|
-
"instructions": "Research the company in this row and return JSON with icp_fit, summary, and risks.",
|
|
156
|
-
"mode": "agent",
|
|
157
|
-
"temperature": 0.7,
|
|
158
|
-
"batchSize": 50,
|
|
159
|
-
"promptSource": "generated",
|
|
160
|
-
"useCompanyContext": True,
|
|
161
|
-
"structuredOutput": True,
|
|
162
|
-
"useAutoSchema": True,
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
"add_to_crm": {
|
|
166
|
-
"key": "add_to_leads",
|
|
167
|
-
"label": "Add to Leads",
|
|
168
|
-
"kind": "enrichment",
|
|
169
|
-
"dataType": "json",
|
|
170
|
-
"origin": "manual",
|
|
171
|
-
"autoRun": "onSourceUpdate",
|
|
172
|
-
"config": {
|
|
173
|
-
"provider": "add_to_crm",
|
|
174
|
-
"leadSource": "research_table_export",
|
|
175
|
-
"fieldMappings": {
|
|
176
|
-
"mode": "single",
|
|
177
|
-
"linkedinUrl": "linkedin_url",
|
|
178
|
-
"companyDomain": "domain",
|
|
179
|
-
"firstName": "first_name",
|
|
180
|
-
"lastName": "last_name",
|
|
181
|
-
"title": "title",
|
|
182
|
-
"companyName": "company",
|
|
183
|
-
"emailAddresses": [{"column": "work_email", "type": "work"}],
|
|
184
|
-
"phoneNumbers": [{"column": "mobile_phone", "type": "mobile"}],
|
|
185
|
-
},
|
|
186
|
-
"sourceColumns": [
|
|
187
|
-
"linkedin_url",
|
|
188
|
-
"domain",
|
|
189
|
-
"first_name",
|
|
190
|
-
"last_name",
|
|
191
|
-
"title",
|
|
192
|
-
"company",
|
|
193
|
-
"work_email",
|
|
194
|
-
"mobile_phone",
|
|
195
|
-
],
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
"sync_to_table": {
|
|
199
|
-
"key": "sync_to_table",
|
|
200
|
-
"label": "Sync to Table",
|
|
201
|
-
"kind": "enrichment",
|
|
202
|
-
"dataType": "json",
|
|
203
|
-
"origin": "manual",
|
|
204
|
-
"autoRun": "onSourceUpdate",
|
|
205
|
-
"config": {
|
|
206
|
-
"provider": "sync_to_table",
|
|
207
|
-
"destinationTableId": "<DESTINATION_TABLE_ID>",
|
|
208
|
-
"columnMappings": [
|
|
209
|
-
{"sourceKey": "company", "destKey": "company"},
|
|
210
|
-
{"sourceKey": "domain", "destKey": "company_domain"},
|
|
211
|
-
{"sourceKey": "work_email", "destKey": "work_email"},
|
|
212
|
-
],
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
"add_to_sequence": {
|
|
216
|
-
"key": "add_to_sequence",
|
|
217
|
-
"label": "Add to Sequence",
|
|
218
|
-
"kind": "enrichment",
|
|
219
|
-
"dataType": "json",
|
|
220
|
-
"origin": "manual",
|
|
221
|
-
"autoRun": "onSourceUpdate",
|
|
222
|
-
"config": {
|
|
223
|
-
"provider": "add_to_sequence",
|
|
224
|
-
"sequenceId": "<SEQUENCE_ID>",
|
|
225
|
-
"sourceLeadColumn": "add_to_leads",
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
}
|
|
229
91
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
"Manual/basic prompts should use explicit placeholders like {{company_name}}, {{domain}}, or {{user_value_proposition}} when those values are needed.",
|
|
246
|
-
"Agent mode is JSON-oriented.",
|
|
247
|
-
"Basic mode can be text or JSON; JSON requires dataType=json.",
|
|
248
|
-
],
|
|
249
|
-
"add_to_crm": [
|
|
250
|
-
"companyDomain is required; LinkedIn is optional.",
|
|
251
|
-
"Include at least one usable hard-identity mapping such as LinkedIn, email, or phone.",
|
|
252
|
-
"If companyDomain is missing in the table, derive or enrich that domain column first.",
|
|
253
|
-
"Add to CRM is optional and non-billable.",
|
|
254
|
-
],
|
|
255
|
-
"sync_to_table": [
|
|
256
|
-
"Use destinationTableId + columnMappings for single-destination sync.",
|
|
257
|
-
"Router mode is supported via config.routes[] (first matching route wins).",
|
|
258
|
-
],
|
|
259
|
-
"add_to_sequence": [
|
|
260
|
-
"sourceLeadColumn should reference the source column key that stores lead IDs (for example add_to_leads), not the provider name add_to_crm.",
|
|
261
|
-
"Set sequenceId to the target workflow sequence ID.",
|
|
262
|
-
"The target sequence must already be ACTIVE for real enrollment.",
|
|
263
|
-
],
|
|
264
|
-
}
|
|
92
|
+
def _build_column_recipe_catalog() -> Tuple[Dict[str, Dict[str, Any]], Dict[str, List[str]]]:
|
|
93
|
+
recipes: Dict[str, Dict[str, Any]] = {}
|
|
94
|
+
notes: Dict[str, List[str]] = {}
|
|
95
|
+
for recipe_type in COLUMN_RECIPE_TYPES:
|
|
96
|
+
contract = get_recipe_contract(recipe_type)
|
|
97
|
+
if not contract:
|
|
98
|
+
continue
|
|
99
|
+
payload = contract.recipe_payload_copy()
|
|
100
|
+
if isinstance(payload, dict):
|
|
101
|
+
recipes[recipe_type] = payload
|
|
102
|
+
notes[recipe_type] = contract.recipe_notes_list()
|
|
103
|
+
return recipes, notes
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
COLUMN_CREATE_RECIPES, COLUMN_RECIPE_NOTES = _build_column_recipe_catalog()
|
|
265
107
|
|
|
266
108
|
SEQUENCE_RECIPE_TYPES = [
|
|
267
109
|
"create",
|
|
@@ -3589,6 +3431,8 @@ def cmd_capabilities(args: argparse.Namespace) -> None:
|
|
|
3589
3431
|
output_contract = llm.get("output_contract") if isinstance(llm.get("output_contract"), dict) else {}
|
|
3590
3432
|
agent_contract = output_contract.get("agent") if isinstance(output_contract.get("agent"), dict) else {}
|
|
3591
3433
|
basic_contract = output_contract.get("basic") if isinstance(output_contract.get("basic"), dict) else {}
|
|
3434
|
+
automation = data.get("automation") if isinstance(data.get("automation"), dict) else {}
|
|
3435
|
+
providers = automation.get("providers") if isinstance(automation.get("providers"), dict) else {}
|
|
3592
3436
|
|
|
3593
3437
|
print(f"API version : {_as_display(data.get('api_version'))}")
|
|
3594
3438
|
print(f"Base URL : {_as_display(data.get('base_url'))}")
|
|
@@ -3612,7 +3456,13 @@ def cmd_capabilities(args: argparse.Namespace) -> None:
|
|
|
3612
3456
|
basic_types = basic_contract.get("supported_data_types")
|
|
3613
3457
|
basic_types_str = ", ".join(str(t) for t in basic_types) if isinstance(basic_types, list) else "text/json"
|
|
3614
3458
|
print(f"basic : {basic_types_str} (JSON requires dataType=json)")
|
|
3459
|
+
if providers:
|
|
3460
|
+
print("")
|
|
3461
|
+
print("Provider setup")
|
|
3462
|
+
print("--------------")
|
|
3463
|
+
print(", ".join(sorted(str(name) for name in providers.keys())))
|
|
3615
3464
|
print("")
|
|
3465
|
+
print("Tip: inspect automation.providers in JSON output for provider-specific setup contracts.")
|
|
3616
3466
|
print("Tip: for JSON enrichment columns, run with `--wait` and verify terminal status before `autotouch columns projections`.")
|
|
3617
3467
|
return
|
|
3618
3468
|
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: autotouch-cli
|
|
3
|
+
Version: 0.2.32
|
|
4
|
+
Summary: Autotouch Smart Table CLI
|
|
5
|
+
Requires-Python: >=3.9
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: requests>=2.31.0
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
9
|
+
|
|
1
10
|
# Autotouch CLI Reference (`autotouch`)
|
|
2
11
|
|
|
3
12
|
This page documents the installable CLI for the Smart Table developer API.
|
|
@@ -506,8 +515,8 @@ autotouch columns create --table-id <TABLE_ID> --data-file <payload.json>
|
|
|
506
515
|
```
|
|
507
516
|
|
|
508
517
|
Recommendation:
|
|
509
|
-
- For provider-backed
|
|
510
|
-
|
|
518
|
+
- For provider-backed or generated columns, start with `autotouch columns recipe`.
|
|
519
|
+
- Built-in recipe types now include `formatter`, `llm_enrichment`, `email_finder`, `phone_finder`, `lead_finder`, `add_to_crm`, `sync_to_table`, and `add_to_sequence`.
|
|
511
520
|
- Email/phone enrichment does not require creating `add_to_crm` first.
|
|
512
521
|
- `add_to_crm` is an optional, non-billable export action.
|
|
513
522
|
|
|
@@ -772,6 +781,7 @@ Notes:
|
|
|
772
781
|
Add-to-Leads note: `companyDomain` is required; LinkedIn is optional. Each row still needs at least one usable hard identity signal (LinkedIn, email, or phone). Names and location fields are metadata only for this flow. Run is non-billable.
|
|
773
782
|
If `companyDomain` is missing in the table, derive or enrich that domain column first, then rerun `add_to_crm`.
|
|
774
783
|
Queued lifecycle: the CLI/API accepts the run immediately, then the backend hands off `ops -> data_io` for execution.
|
|
784
|
+
Creating `add_to_crm` after upstream email/phone/lead columns already finished does not replay those older updates. In that case, run `add_to_crm` explicitly or rerun the upstream source column.
|
|
775
785
|
|
|
776
786
|
CRM data model expectations (recommended before `add_to_crm`):
|
|
777
787
|
- Lead identity/dedupe expects `company_domain` plus one usable hard identity signal. `linkedin_url` is a strong optional signal, not a requirement.
|
|
@@ -810,6 +820,14 @@ CRM data model expectations (recommended before `add_to_crm`):
|
|
|
810
820
|
Notes:
|
|
811
821
|
- Single-destination mode uses `destinationTableId` + `columnMappings`.
|
|
812
822
|
- Router mode is also supported with `config.routes[]` (top-to-bottom matching, first hit wins, default route catches unmatched rows).
|
|
823
|
+
- Route conditions are evaluated against the parent/source row, not against each list item.
|
|
824
|
+
- `autoRun: "onSourceUpdate"` means dependency-driven runs from source row inserts/updates. Saving the column does not backfill existing rows for `sync_to_table`; use an explicit column run/backfill when needed.
|
|
825
|
+
- List mode uses `syncMode: "list"` with `listSourceColumnId` and optional `listPath` (default `items`) to expand a canonical JSON payload like `{ "items": [...], "reasoning": "..." }`.
|
|
826
|
+
- In list mode:
|
|
827
|
+
- `sourceScope: "item"` maps fields from each `items[]` object.
|
|
828
|
+
- `sourceScope: "row"` maps fields from the parent/source row.
|
|
829
|
+
- Explicit item mappings are still recommended for renamed fields such as `name -> full_name`.
|
|
830
|
+
- Blank placeholder list items are skipped and do not create destination rows.
|
|
813
831
|
|
|
814
832
|
### 8) `add_to_sequence`
|
|
815
833
|
|
|
@@ -835,10 +853,33 @@ Notes:
|
|
|
835
853
|
- `sourceLeadColumn` must be the source column key that stores lead IDs (for example `add_to_leads` or another lead-id column key from `lead_finder` output), not the provider name `add_to_crm`.
|
|
836
854
|
- `sequenceId` is the target sequence workflow ID.
|
|
837
855
|
- The target sequence must already be `ACTIVE` for real enrollment. Table `add_to_sequence` runs and direct `POST /api/sequences/{id}/enroll` share the same activation check.
|
|
856
|
+
- Common tail order after contact rows or lead IDs exist is `email_finder -> add_to_crm -> create/activate sequence -> add_to_sequence`.
|
|
857
|
+
- Creating `add_to_sequence` after lead IDs already exist does not replay those older updates. In that case, run `add_to_sequence` explicitly or rerun the lead-id source column.
|
|
838
858
|
- `add_to_sequence` runs auto-attach `research_context.source_table_id` (and table name when available). Field selection stays implicit so sequence drafts/audience resolve favorites from current starred columns by default.
|
|
839
859
|
- Star/favorite the highest-signal fields so callers can see them quickly in the sidecar during live call workflows.
|
|
840
860
|
- The same favorite set is also the default AI drafting context when explicit `fieldIds` are not provided.
|
|
841
861
|
|
|
862
|
+
## Example pipeline: LLM items -> contacts table -> leads -> sequence
|
|
863
|
+
|
|
864
|
+
Use this when an LLM column returns canonical JSON like `{ "items": [...] }` and each item should become a contact row.
|
|
865
|
+
This is an example pattern, not the default recommendation for all person discovery.
|
|
866
|
+
Use `lead_finder` first when the goal is explicit buyer/lead discovery with clear role targeting at scale.
|
|
867
|
+
Use agent `llm_enrichment` when the workflow needs custom research output, website-discovered contacts, or low-coverage / hard-to-find cases.
|
|
868
|
+
|
|
869
|
+
1. Create the source table and import company rows.
|
|
870
|
+
2. Create the LLM enrichment column that outputs `items[]`.
|
|
871
|
+
3. Create `sync_to_table` in `list` mode:
|
|
872
|
+
- set `listSourceColumnId` to the LLM column ID
|
|
873
|
+
- keep item fields on `sourceScope: "item"`
|
|
874
|
+
- keep parent company metadata on `sourceScope: "row"`
|
|
875
|
+
4. Run or wait for `sync_to_table` so the destination contacts table has rows.
|
|
876
|
+
5. On the destination contacts table, create and run `email_finder`.
|
|
877
|
+
6. Create `add_to_crm` on that same destination contacts table.
|
|
878
|
+
7. If email finder already finished before `add_to_crm` existed, run `add_to_crm` explicitly.
|
|
879
|
+
8. Create the target sequence and set it `ACTIVE`.
|
|
880
|
+
9. Create `add_to_sequence` with `sourceLeadColumn` set to the lead-id column key, usually `add_to_leads`.
|
|
881
|
+
10. If leads already existed before `add_to_sequence` was created, run `add_to_sequence` explicitly.
|
|
882
|
+
|
|
842
883
|
## Common workflow
|
|
843
884
|
|
|
844
885
|
```bash
|
|
@@ -1150,6 +1191,7 @@ Agent expectations:
|
|
|
1150
1191
|
- `column_types` tells you which column types are runnable and which are non-billable transforms (`json_split`, `formatter_formula`).
|
|
1151
1192
|
- `filtering` describes valid scope/filter semantics for estimate/run.
|
|
1152
1193
|
- `automation.auto_run` describes supported auto-run modes + config field names.
|
|
1194
|
+
- `automation.providers` exposes provider-specific setup contracts, save-time backfill behavior, dispatch strategy, and recipe type names for formatter/LLM/finders/action columns.
|
|
1153
1195
|
- `execution_policies.llm.output_contract` describes output behavior by mode:
|
|
1154
1196
|
- `agent` => JSON-oriented structured output
|
|
1155
1197
|
- `basic` => text or JSON (`dataType=json` for structured JSON output)
|
|
@@ -7,6 +7,8 @@ autotouch_cli.egg-info/dependency_links.txt
|
|
|
7
7
|
autotouch_cli.egg-info/entry_points.txt
|
|
8
8
|
autotouch_cli.egg-info/requires.txt
|
|
9
9
|
autotouch_cli.egg-info/top_level.txt
|
|
10
|
+
autotouch_shared/__init__.py
|
|
11
|
+
autotouch_shared/provider_registry.py
|
|
10
12
|
docs/research-table/reference/autotouch-cli.md
|
|
11
13
|
tests/test_column_prompt_compiler.py
|
|
12
14
|
tests/test_contactout_custom.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Shared Autotouch contracts and metadata."""
|