autotouch-cli 0.2.87__tar.gz → 0.2.90__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.87 → autotouch_cli-0.2.90}/PKG-INFO +16 -2
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/README.md +15 -1
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/agents.py +36 -19
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/data/CLI_REFERENCE.md +9 -9
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/data/cli-manifest.json +13 -9
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/templates.py +183 -17
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli.egg-info/PKG-INFO +16 -2
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_shared/provider_registry.py +45 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/pyproject.toml +1 -1
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/MANIFEST.in +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/__init__.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/cli.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/cli_contracts.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/__init__.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/auth.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/cells.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/columns.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/jobs.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/leads.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/linkedin.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/list_build.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/prompts.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/rows.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/search.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/sequences.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/tables.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/tasks.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/webhooks.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/commands/workspace_secrets.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/__init__.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/auth.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/config.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/csv_import.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/http.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/io.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/output.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/polling.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/run.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/core/validation.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/exceptions.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/mongo_status.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/parser.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/parser_groups.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli/sequence_support.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli.egg-info/SOURCES.txt +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli.egg-info/dependency_links.txt +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli.egg-info/entry_points.txt +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli.egg-info/requires.txt +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_cli.egg-info/top_level.txt +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_shared/__init__.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_shared/linkedin_contract.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_shared/linkedin_filters.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_shared/list_build_contract.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/autotouch_shared/search_contract.py +0 -0
- {autotouch_cli-0.2.87 → autotouch_cli-0.2.90}/setup.cfg +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.90
|
|
4
4
|
Summary: Autotouch Smart Table CLI
|
|
5
5
|
Project-URL: Homepage, https://app.autotouch.ai
|
|
6
6
|
Project-URL: Documentation, https://github.com/nicolonic/autotouch_main/tree/main/docs/research-table/reference
|
|
@@ -36,6 +36,8 @@ For a shipped human-readable reference generated from the installed parser, use
|
|
|
36
36
|
|
|
37
37
|
## Install
|
|
38
38
|
|
|
39
|
+
Released package:
|
|
40
|
+
|
|
39
41
|
```bash
|
|
40
42
|
pipx install autotouch-cli
|
|
41
43
|
# or
|
|
@@ -44,6 +46,16 @@ pip install autotouch-cli
|
|
|
44
46
|
pip install -U autotouch-cli
|
|
45
47
|
```
|
|
46
48
|
|
|
49
|
+
Unreleased branch or pre-publish build:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pipx install --force "git+ssh://git@github.com/nicolonic/autotouch_main.git@<branch-or-sha>"
|
|
53
|
+
# or
|
|
54
|
+
python -m pip install -U "git+ssh://git@github.com/nicolonic/autotouch_main.git@<branch-or-sha>"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The `autotouch-cli` package name installs the latest published package from the configured package index. Use the git/source install form when testing a version bump before the release tag has published.
|
|
58
|
+
|
|
47
59
|
## First Run
|
|
48
60
|
|
|
49
61
|
Existing developer key:
|
|
@@ -158,13 +170,15 @@ For structured company builds, start with industry IDs plus geo/company-size fil
|
|
|
158
170
|
|
|
159
171
|
For account-first prospecting from LinkedIn/Sales Navigator, build companies/accounts first, inspect the returned company IDs, then pass those IDs to `autotouch list-build leads --current-company-id ...`. Do not use Exa company search as a default pre-step for every LinkedIn list build; use it when the user's target is genuinely semantic, niche, competitor-based, or not meant to be LinkedIn-sourced.
|
|
160
172
|
|
|
173
|
+
Use `autotouch agents ...` for recurring signal-based discovery. Scheduled agents support `--target ACCOUNTS` for company/account output and `--target LEADS` for people output. Every agent writes a source/signal table for the evidence it used; lead agents then write `candidate_research.candidates[]` on source rows and list-sync those candidates into the lead/candidate output table. See the agent playbook for the full source-table and candidate-sync contract.
|
|
174
|
+
|
|
161
175
|
## More
|
|
162
176
|
|
|
163
177
|
For automation or agent-driven setup, use:
|
|
164
178
|
- `autotouch cli-manifest --output json` for the local machine-readable command contract
|
|
165
179
|
- `autotouch cli-reference` for the shipped parser-generated reference
|
|
166
180
|
- `autotouch capabilities --output json` for provider/workflow contracts
|
|
167
|
-
- `autotouch --version` should be `0.2.
|
|
181
|
+
- `autotouch --version` should be `0.2.90` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, and V2 sequence flowGraph recipes
|
|
168
182
|
- `autotouch capabilities --output json --select list_builds` for documented list-build inputs such as geography IDs, company size buckets, profile language, and company IDs
|
|
169
183
|
- `autotouch list-build inputs` and `autotouch list-build pricing` before creating durable list-build jobs
|
|
170
184
|
- `autotouch list-build companies` and `autotouch list-build leads` for durable LinkedIn-sourced company and lead list builds with Smart Table-owned background workers, visible progress, and no user-owned LinkedIn connection requirement
|
|
@@ -11,6 +11,8 @@ For a shipped human-readable reference generated from the installed parser, use
|
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
14
|
+
Released package:
|
|
15
|
+
|
|
14
16
|
```bash
|
|
15
17
|
pipx install autotouch-cli
|
|
16
18
|
# or
|
|
@@ -19,6 +21,16 @@ pip install autotouch-cli
|
|
|
19
21
|
pip install -U autotouch-cli
|
|
20
22
|
```
|
|
21
23
|
|
|
24
|
+
Unreleased branch or pre-publish build:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pipx install --force "git+ssh://git@github.com/nicolonic/autotouch_main.git@<branch-or-sha>"
|
|
28
|
+
# or
|
|
29
|
+
python -m pip install -U "git+ssh://git@github.com/nicolonic/autotouch_main.git@<branch-or-sha>"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The `autotouch-cli` package name installs the latest published package from the configured package index. Use the git/source install form when testing a version bump before the release tag has published.
|
|
33
|
+
|
|
22
34
|
## First Run
|
|
23
35
|
|
|
24
36
|
Existing developer key:
|
|
@@ -133,13 +145,15 @@ For structured company builds, start with industry IDs plus geo/company-size fil
|
|
|
133
145
|
|
|
134
146
|
For account-first prospecting from LinkedIn/Sales Navigator, build companies/accounts first, inspect the returned company IDs, then pass those IDs to `autotouch list-build leads --current-company-id ...`. Do not use Exa company search as a default pre-step for every LinkedIn list build; use it when the user's target is genuinely semantic, niche, competitor-based, or not meant to be LinkedIn-sourced.
|
|
135
147
|
|
|
148
|
+
Use `autotouch agents ...` for recurring signal-based discovery. Scheduled agents support `--target ACCOUNTS` for company/account output and `--target LEADS` for people output. Every agent writes a source/signal table for the evidence it used; lead agents then write `candidate_research.candidates[]` on source rows and list-sync those candidates into the lead/candidate output table. See the agent playbook for the full source-table and candidate-sync contract.
|
|
149
|
+
|
|
136
150
|
## More
|
|
137
151
|
|
|
138
152
|
For automation or agent-driven setup, use:
|
|
139
153
|
- `autotouch cli-manifest --output json` for the local machine-readable command contract
|
|
140
154
|
- `autotouch cli-reference` for the shipped parser-generated reference
|
|
141
155
|
- `autotouch capabilities --output json` for provider/workflow contracts
|
|
142
|
-
- `autotouch --version` should be `0.2.
|
|
156
|
+
- `autotouch --version` should be `0.2.90` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, and V2 sequence flowGraph recipes
|
|
143
157
|
- `autotouch capabilities --output json --select list_builds` for documented list-build inputs such as geography IDs, company size buckets, profile language, and company IDs
|
|
144
158
|
- `autotouch list-build inputs` and `autotouch list-build pricing` before creating durable list-build jobs
|
|
145
159
|
- `autotouch list-build companies` and `autotouch list-build leads` for durable LinkedIn-sourced company and lead list builds with Smart Table-owned background workers, visible progress, and no user-owned LinkedIn connection requirement
|
|
@@ -10,6 +10,9 @@ from dataclasses import dataclass
|
|
|
10
10
|
from typing import Any, Callable, Dict, Optional, Sequence
|
|
11
11
|
|
|
12
12
|
|
|
13
|
+
AGENT_TARGET_CHOICES = ["LEADS", "ACCOUNTS"]
|
|
14
|
+
|
|
15
|
+
|
|
13
16
|
@dataclass(frozen=True)
|
|
14
17
|
class AgentCommandRuntime:
|
|
15
18
|
resolve_token: Callable[[Optional[str], bool], Optional[str]]
|
|
@@ -50,7 +53,12 @@ def cmd_agents_create(args: argparse.Namespace, *, runtime: AgentCommandRuntime)
|
|
|
50
53
|
token = runtime.resolve_token(args.token, required=True)
|
|
51
54
|
|
|
52
55
|
if getattr(args, "from_file", None):
|
|
53
|
-
payload = runtime.load_json_input(
|
|
56
|
+
payload = runtime.load_json_input(
|
|
57
|
+
inline_json=None,
|
|
58
|
+
file_path=args.from_file,
|
|
59
|
+
context="agent",
|
|
60
|
+
default={},
|
|
61
|
+
)
|
|
54
62
|
else:
|
|
55
63
|
payload: Dict[str, Any] = {}
|
|
56
64
|
if args.name:
|
|
@@ -106,7 +114,7 @@ def cmd_agents_create(args: argparse.Namespace, *, runtime: AgentCommandRuntime)
|
|
|
106
114
|
|
|
107
115
|
# AI generation: generate persona, signals, and create in one shot
|
|
108
116
|
if getattr(args, "generate", False) and "personaConfig" not in payload:
|
|
109
|
-
target = payload.get("targetType"
|
|
117
|
+
target = str(payload.get("targetType") or "LEADS").upper()
|
|
110
118
|
sys.stderr.write(f"Generating persona for {target}...\n")
|
|
111
119
|
persona_data = runtime.request_api(
|
|
112
120
|
"POST", "/api/agents/generate-persona",
|
|
@@ -119,17 +127,21 @@ def cmd_agents_create(args: argparse.Namespace, *, runtime: AgentCommandRuntime)
|
|
|
119
127
|
payload["personaConfig"] = persona
|
|
120
128
|
sys.stderr.write(f" Persona generated: {json.dumps(persona, ensure_ascii=False)[:200]}...\n")
|
|
121
129
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
topics = []
|
|
131
|
+
if target == "LEADS":
|
|
132
|
+
# LinkedIn topic engagement is a people-output signal. Account
|
|
133
|
+
# agents should stick to company-compatible signals such as jobs
|
|
134
|
+
# and news until a company-output topic signal exists.
|
|
135
|
+
sys.stderr.write("Generating topic suggestions...\n")
|
|
136
|
+
topic_data = runtime.request_api(
|
|
137
|
+
"POST", "/api/agents/generate-signal-topics",
|
|
138
|
+
base_url=args.base_url, token=token,
|
|
139
|
+
use_x_api_key=args.use_x_api_key,
|
|
140
|
+
payload={"targetType": target, "personaConfig": persona},
|
|
141
|
+
timeout=args.timeout, verbose=args.verbose,
|
|
142
|
+
)
|
|
143
|
+
topics = topic_data.get("topics") or []
|
|
144
|
+
sys.stderr.write(f" Topics: {topics}\n")
|
|
133
145
|
|
|
134
146
|
# Generate job signal
|
|
135
147
|
sys.stderr.write("Generating job signal config...\n")
|
|
@@ -146,7 +158,7 @@ def cmd_agents_create(args: argparse.Namespace, *, runtime: AgentCommandRuntime)
|
|
|
146
158
|
|
|
147
159
|
# Assemble signals
|
|
148
160
|
signals = []
|
|
149
|
-
if topics:
|
|
161
|
+
if target == "LEADS" and topics:
|
|
150
162
|
signals.append({
|
|
151
163
|
"key": "linkedin-topic-post-engagement",
|
|
152
164
|
"config": {"topics": [{"id": "", "label": t, "trackingMode": "all"} for t in topics[:5]]},
|
|
@@ -184,7 +196,12 @@ def cmd_agents_update(args: argparse.Namespace, *, runtime: AgentCommandRuntime)
|
|
|
184
196
|
token = runtime.resolve_token(args.token, required=True)
|
|
185
197
|
|
|
186
198
|
if getattr(args, "from_file", None):
|
|
187
|
-
payload = runtime.load_json_input(
|
|
199
|
+
payload = runtime.load_json_input(
|
|
200
|
+
inline_json=None,
|
|
201
|
+
file_path=args.from_file,
|
|
202
|
+
context="agent",
|
|
203
|
+
default={},
|
|
204
|
+
)
|
|
188
205
|
else:
|
|
189
206
|
payload: Dict[str, Any] = {}
|
|
190
207
|
if getattr(args, "name", None):
|
|
@@ -447,7 +464,7 @@ def register_agents_subcommands(
|
|
|
447
464
|
# -- create --
|
|
448
465
|
pac = agents_sub.add_parser("create", help="Create a new agent")
|
|
449
466
|
pac.add_argument("--name", help="Agent name")
|
|
450
|
-
pac.add_argument("--target", choices=
|
|
467
|
+
pac.add_argument("--target", choices=AGENT_TARGET_CHOICES, help="Target type")
|
|
451
468
|
pac.add_argument("--assigned-user", dest="assigned_user", help="Assigned user ID")
|
|
452
469
|
pac.add_argument("--schedule-time", dest="schedule_time", help="Time of day (HH:MM) — used by daily/weekly")
|
|
453
470
|
pac.add_argument("--schedule-tz", dest="schedule_tz", help="Timezone (default: UTC)")
|
|
@@ -585,14 +602,14 @@ def register_agents_subcommands(
|
|
|
585
602
|
|
|
586
603
|
# -- generate-persona --
|
|
587
604
|
pagp = agents_sub.add_parser("generate-persona", help="Generate ICP persona config via AI")
|
|
588
|
-
pagp.add_argument("--target", choices=
|
|
605
|
+
pagp.add_argument("--target", choices=AGENT_TARGET_CHOICES, default="LEADS", help="Target type")
|
|
589
606
|
pagp.add_argument("--current-config", dest="current_config", help="Path to current persona config JSON")
|
|
590
607
|
add_api_common_arguments(pagp)
|
|
591
608
|
pagp.set_defaults(func=handlers["generate_persona"])
|
|
592
609
|
|
|
593
610
|
# -- generate-topics --
|
|
594
611
|
pagt = agents_sub.add_parser("generate-topics", help="Generate signal topic suggestions via AI")
|
|
595
|
-
pagt.add_argument("--target", choices=
|
|
612
|
+
pagt.add_argument("--target", choices=AGENT_TARGET_CHOICES, default="LEADS", help="Target type")
|
|
596
613
|
pagt.add_argument("--persona", help="Path to persona config JSON")
|
|
597
614
|
pagt.add_argument("--current-topics", dest="current_topics", help="Comma-separated current topics")
|
|
598
615
|
add_api_common_arguments(pagt)
|
|
@@ -600,7 +617,7 @@ def register_agents_subcommands(
|
|
|
600
617
|
|
|
601
618
|
# -- generate-job-signal --
|
|
602
619
|
pagj = agents_sub.add_parser("generate-job-signal", help="Generate job signal config via AI")
|
|
603
|
-
pagj.add_argument("--target", choices=
|
|
620
|
+
pagj.add_argument("--target", choices=AGENT_TARGET_CHOICES, default="LEADS", help="Target type")
|
|
604
621
|
pagj.add_argument("--persona", help="Path to persona config JSON")
|
|
605
622
|
pagj.add_argument("--current-titles", dest="current_titles", help="Comma-separated current job titles")
|
|
606
623
|
pagj.add_argument("--current-keywords", dest="current_keywords", help="Comma-separated current keywords")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Autotouch CLI Reference
|
|
2
2
|
|
|
3
|
-
Generated from the installed parser for `autotouch-cli` `0.2.
|
|
3
|
+
Generated from the installed parser for `autotouch-cli` `0.2.90`.
|
|
4
4
|
Manifest schema version: `2`.
|
|
5
5
|
|
|
6
6
|
## Output Modes
|
|
@@ -34,7 +34,7 @@ Create a new agent
|
|
|
34
34
|
- Destructive: `no`
|
|
35
35
|
- Output modes: `json, ndjson, human`
|
|
36
36
|
- Example:
|
|
37
|
-
- `autotouch agents create [-h] [--name NAME] [--target {LEADS}]
|
|
37
|
+
- `autotouch agents create [-h] [--name NAME] [--target {LEADS,ACCOUNTS}]
|
|
38
38
|
[--assigned-user ASSIGNED_USER]
|
|
39
39
|
[--schedule-time SCHEDULE_TIME]
|
|
40
40
|
[--schedule-tz SCHEDULE_TZ]
|
|
@@ -56,7 +56,7 @@ Create a new agent
|
|
|
56
56
|
[--verbose]`
|
|
57
57
|
- Options:
|
|
58
58
|
- `--name` (kind=string): Agent name
|
|
59
|
-
- `--target` (kind=string; choices=LEADS): Target type
|
|
59
|
+
- `--target` (kind=string; choices=LEADS,ACCOUNTS): Target type
|
|
60
60
|
- `--assigned-user` (kind=string): Assigned user ID
|
|
61
61
|
- `--schedule-time` (kind=string): Time of day (HH:MM) — used by daily/weekly
|
|
62
62
|
- `--schedule-tz` (kind=string): Timezone (default: UTC)
|
|
@@ -118,7 +118,7 @@ Generate job signal config via AI
|
|
|
118
118
|
- Destructive: `no`
|
|
119
119
|
- Output modes: `json, ndjson, human`
|
|
120
120
|
- Example:
|
|
121
|
-
- `autotouch agents generate-job-signal [-h] [--target {LEADS}]
|
|
121
|
+
- `autotouch agents generate-job-signal [-h] [--target {LEADS,ACCOUNTS}]
|
|
122
122
|
[--persona PERSONA]
|
|
123
123
|
[--current-titles CURRENT_TITLES]
|
|
124
124
|
[--current-keywords CURRENT_KEYWORDS]
|
|
@@ -130,7 +130,7 @@ Generate job signal config via AI
|
|
|
130
130
|
--json-pointer JSON_POINTER]
|
|
131
131
|
[--verbose]`
|
|
132
132
|
- Options:
|
|
133
|
-
- `--target` (kind=string; choices=LEADS; default=LEADS): Target type
|
|
133
|
+
- `--target` (kind=string; choices=LEADS,ACCOUNTS; default=LEADS): Target type
|
|
134
134
|
- `--persona` (kind=string): Path to persona config JSON
|
|
135
135
|
- `--current-titles` (kind=string; comma-separated): Comma-separated current job titles
|
|
136
136
|
- `--current-keywords` (kind=string; comma-separated): Comma-separated current keywords
|
|
@@ -153,7 +153,7 @@ Generate ICP persona config via AI
|
|
|
153
153
|
- Destructive: `no`
|
|
154
154
|
- Output modes: `json, ndjson, human`
|
|
155
155
|
- Example:
|
|
156
|
-
- `autotouch agents generate-persona [-h] [--target {LEADS}]
|
|
156
|
+
- `autotouch agents generate-persona [-h] [--target {LEADS,ACCOUNTS}]
|
|
157
157
|
[--current-config CURRENT_CONFIG]
|
|
158
158
|
[--base-url BASE_URL] [--token TOKEN]
|
|
159
159
|
[--use-x-api-key] [--timeout TIMEOUT]
|
|
@@ -162,7 +162,7 @@ Generate ICP persona config via AI
|
|
|
162
162
|
--json-pointer JSON_POINTER]
|
|
163
163
|
[--verbose]`
|
|
164
164
|
- Options:
|
|
165
|
-
- `--target` (kind=string; choices=LEADS; default=LEADS): Target type
|
|
165
|
+
- `--target` (kind=string; choices=LEADS,ACCOUNTS; default=LEADS): Target type
|
|
166
166
|
- `--current-config` (kind=string): Path to current persona config JSON
|
|
167
167
|
- `--base-url` (kind=string; default=https://app.autotouch.ai): API base URL (default: https://app.autotouch.ai)
|
|
168
168
|
- `--token` (kind=string; sensitive): Developer API key / JWT token
|
|
@@ -183,7 +183,7 @@ Generate signal topic suggestions via AI
|
|
|
183
183
|
- Destructive: `no`
|
|
184
184
|
- Output modes: `json, ndjson, human`
|
|
185
185
|
- Example:
|
|
186
|
-
- `autotouch agents generate-topics [-h] [--target {LEADS}]
|
|
186
|
+
- `autotouch agents generate-topics [-h] [--target {LEADS,ACCOUNTS}]
|
|
187
187
|
[--persona PERSONA]
|
|
188
188
|
[--current-topics CURRENT_TOPICS]
|
|
189
189
|
[--base-url BASE_URL] [--token TOKEN]
|
|
@@ -193,7 +193,7 @@ Generate signal topic suggestions via AI
|
|
|
193
193
|
--json-pointer JSON_POINTER]
|
|
194
194
|
[--verbose]`
|
|
195
195
|
- Options:
|
|
196
|
-
- `--target` (kind=string; choices=LEADS; default=LEADS): Target type
|
|
196
|
+
- `--target` (kind=string; choices=LEADS,ACCOUNTS; default=LEADS): Target type
|
|
197
197
|
- `--persona` (kind=string): Path to persona config JSON
|
|
198
198
|
- `--current-topics` (kind=string; comma-separated): Comma-separated current topics
|
|
199
199
|
- `--base-url` (kind=string; default=https://app.autotouch.ai): API base URL (default: https://app.autotouch.ai)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.2.
|
|
2
|
+
"version": "0.2.90",
|
|
3
3
|
"manifest_schema_version": 2,
|
|
4
4
|
"entry_points": {
|
|
5
5
|
"autotouch": "autotouch_cli.cli:main",
|
|
@@ -34796,7 +34796,8 @@
|
|
|
34796
34796
|
"kind": "string",
|
|
34797
34797
|
"action": "store",
|
|
34798
34798
|
"choices": [
|
|
34799
|
-
"LEADS"
|
|
34799
|
+
"LEADS",
|
|
34800
|
+
"ACCOUNTS"
|
|
34800
34801
|
],
|
|
34801
34802
|
"flags": [
|
|
34802
34803
|
"--target"
|
|
@@ -35176,7 +35177,7 @@
|
|
|
35176
35177
|
},
|
|
35177
35178
|
"availability": null,
|
|
35178
35179
|
"examples": [
|
|
35179
|
-
"autotouch agents create [-h] [--name NAME] [--target {LEADS}]\n [--assigned-user ASSIGNED_USER]\n [--schedule-time SCHEDULE_TIME]\n [--schedule-tz SCHEDULE_TZ]\n [--schedule-frequency {hourly,every_6h,every_12h,daily,weekly}]\n [--schedule-days {all,weekdays}]\n [--schedule-day-of-week 0-6]\n [--schedule-window-start SCHEDULE_WINDOW_START]\n [--schedule-window-end SCHEDULE_WINDOW_END]\n [--auto-find-email] [--auto-find-phone]\n [--auto-broaden]\n [--auto-create-lead-mode {qualified_only,everyone,manual_only}]\n [--auto-sequence-id AUTO_SEQUENCE_ID]\n [--status {DRAFT,ACTIVE,PAUSED}]\n [--from-file FROM_FILE] [--generate]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT | --json-pointer JSON_POINTER]\n [--verbose]"
|
|
35180
|
+
"autotouch agents create [-h] [--name NAME] [--target {LEADS,ACCOUNTS}]\n [--assigned-user ASSIGNED_USER]\n [--schedule-time SCHEDULE_TIME]\n [--schedule-tz SCHEDULE_TZ]\n [--schedule-frequency {hourly,every_6h,every_12h,daily,weekly}]\n [--schedule-days {all,weekdays}]\n [--schedule-day-of-week 0-6]\n [--schedule-window-start SCHEDULE_WINDOW_START]\n [--schedule-window-end SCHEDULE_WINDOW_END]\n [--auto-find-email] [--auto-find-phone]\n [--auto-broaden]\n [--auto-create-lead-mode {qualified_only,everyone,manual_only}]\n [--auto-sequence-id AUTO_SEQUENCE_ID]\n [--status {DRAFT,ACTIVE,PAUSED}]\n [--from-file FROM_FILE] [--generate]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT | --json-pointer JSON_POINTER]\n [--verbose]"
|
|
35180
35181
|
],
|
|
35181
35182
|
"stability": "stable",
|
|
35182
35183
|
"handler": "_fn"
|
|
@@ -36348,7 +36349,8 @@
|
|
|
36348
36349
|
"kind": "string",
|
|
36349
36350
|
"action": "store",
|
|
36350
36351
|
"choices": [
|
|
36351
|
-
"LEADS"
|
|
36352
|
+
"LEADS",
|
|
36353
|
+
"ACCOUNTS"
|
|
36352
36354
|
],
|
|
36353
36355
|
"default_when_omitted": "LEADS",
|
|
36354
36356
|
"default": "LEADS",
|
|
@@ -36521,7 +36523,7 @@
|
|
|
36521
36523
|
},
|
|
36522
36524
|
"availability": null,
|
|
36523
36525
|
"examples": [
|
|
36524
|
-
"autotouch agents generate-persona [-h] [--target {LEADS}]\n [--current-config CURRENT_CONFIG]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
36526
|
+
"autotouch agents generate-persona [-h] [--target {LEADS,ACCOUNTS}]\n [--current-config CURRENT_CONFIG]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
36525
36527
|
],
|
|
36526
36528
|
"stability": "stable",
|
|
36527
36529
|
"handler": "_fn"
|
|
@@ -36547,7 +36549,8 @@
|
|
|
36547
36549
|
"kind": "string",
|
|
36548
36550
|
"action": "store",
|
|
36549
36551
|
"choices": [
|
|
36550
|
-
"LEADS"
|
|
36552
|
+
"LEADS",
|
|
36553
|
+
"ACCOUNTS"
|
|
36551
36554
|
],
|
|
36552
36555
|
"default_when_omitted": "LEADS",
|
|
36553
36556
|
"default": "LEADS",
|
|
@@ -36732,7 +36735,7 @@
|
|
|
36732
36735
|
},
|
|
36733
36736
|
"availability": null,
|
|
36734
36737
|
"examples": [
|
|
36735
|
-
"autotouch agents generate-topics [-h] [--target {LEADS}]\n [--persona PERSONA]\n [--current-topics CURRENT_TOPICS]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
36738
|
+
"autotouch agents generate-topics [-h] [--target {LEADS,ACCOUNTS}]\n [--persona PERSONA]\n [--current-topics CURRENT_TOPICS]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
36736
36739
|
],
|
|
36737
36740
|
"stability": "stable",
|
|
36738
36741
|
"handler": "_fn"
|
|
@@ -36758,7 +36761,8 @@
|
|
|
36758
36761
|
"kind": "string",
|
|
36759
36762
|
"action": "store",
|
|
36760
36763
|
"choices": [
|
|
36761
|
-
"LEADS"
|
|
36764
|
+
"LEADS",
|
|
36765
|
+
"ACCOUNTS"
|
|
36762
36766
|
],
|
|
36763
36767
|
"default_when_omitted": "LEADS",
|
|
36764
36768
|
"default": "LEADS",
|
|
@@ -36955,7 +36959,7 @@
|
|
|
36955
36959
|
},
|
|
36956
36960
|
"availability": null,
|
|
36957
36961
|
"examples": [
|
|
36958
|
-
"autotouch agents generate-job-signal [-h] [--target {LEADS}]\n [--persona PERSONA]\n [--current-titles CURRENT_TITLES]\n [--current-keywords CURRENT_KEYWORDS]\n [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
36962
|
+
"autotouch agents generate-job-signal [-h] [--target {LEADS,ACCOUNTS}]\n [--persona PERSONA]\n [--current-titles CURRENT_TITLES]\n [--current-keywords CURRENT_KEYWORDS]\n [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}]\n [--compact] [--select SELECT |\n --json-pointer JSON_POINTER]\n [--verbose]"
|
|
36959
36963
|
],
|
|
36960
36964
|
"stability": "stable",
|
|
36961
36965
|
"handler": "_fn"
|
|
@@ -199,7 +199,7 @@ SEQUENCE_RECIPE_TYPES = [
|
|
|
199
199
|
|
|
200
200
|
SEQUENCE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
201
201
|
"create": {
|
|
202
|
-
"name": "Outbound
|
|
202
|
+
"name": "Outbound flow",
|
|
203
203
|
"sourceTableId": "<TABLE_ID>",
|
|
204
204
|
"sourceTableName": "ICP Prospects",
|
|
205
205
|
"exitRules": {
|
|
@@ -243,20 +243,37 @@ SEQUENCE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
|
243
243
|
"aiDraft": True,
|
|
244
244
|
"scriptTemplate": "",
|
|
245
245
|
},
|
|
246
|
-
{
|
|
247
|
-
"id": "linkedin_1",
|
|
248
|
-
"kind": "LINKEDIN_CHAT_MESSAGE",
|
|
249
|
-
"waitDays": 2,
|
|
250
|
-
"waitHours": 0,
|
|
251
|
-
"waitMinutes": 0,
|
|
252
|
-
"executionMode": "AUTOMATED",
|
|
253
|
-
"aiDraft": True,
|
|
254
|
-
"scriptTemplate": "",
|
|
255
|
-
},
|
|
256
246
|
],
|
|
247
|
+
"flowGraph": {
|
|
248
|
+
"version": 1,
|
|
249
|
+
"nodes": [
|
|
250
|
+
{
|
|
251
|
+
"id": "step:email_1",
|
|
252
|
+
"kind": "action",
|
|
253
|
+
"title": "Send email",
|
|
254
|
+
"sourceStepId": "email_1",
|
|
255
|
+
"position": {"x": 0, "y": 0},
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"id": "step:call_1",
|
|
259
|
+
"kind": "action",
|
|
260
|
+
"title": "Call",
|
|
261
|
+
"sourceStepId": "call_1",
|
|
262
|
+
"position": {"x": 0, "y": 160},
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
"edges": [
|
|
266
|
+
{
|
|
267
|
+
"id": "edge:email_1:call_1",
|
|
268
|
+
"source": "step:email_1",
|
|
269
|
+
"target": "step:call_1",
|
|
270
|
+
"kind": "next",
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
257
274
|
},
|
|
258
275
|
"bulk_automated": {
|
|
259
|
-
"name": "Bulk outbound
|
|
276
|
+
"name": "Bulk outbound flow",
|
|
260
277
|
"sourceTableId": "<TABLE_ID>",
|
|
261
278
|
"sourceTableName": "ICP Prospects",
|
|
262
279
|
"exitRules": {
|
|
@@ -302,9 +319,36 @@ SEQUENCE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
|
302
319
|
"bodyTemplate": "Hi {{first_name}}, circling back on this.",
|
|
303
320
|
},
|
|
304
321
|
],
|
|
322
|
+
"flowGraph": {
|
|
323
|
+
"version": 1,
|
|
324
|
+
"nodes": [
|
|
325
|
+
{
|
|
326
|
+
"id": "step:email_1",
|
|
327
|
+
"kind": "action",
|
|
328
|
+
"title": "Send first email",
|
|
329
|
+
"sourceStepId": "email_1",
|
|
330
|
+
"position": {"x": 0, "y": 0},
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
"id": "step:email_2",
|
|
334
|
+
"kind": "action",
|
|
335
|
+
"title": "Follow-up email",
|
|
336
|
+
"sourceStepId": "email_2",
|
|
337
|
+
"position": {"x": 0, "y": 160},
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
"edges": [
|
|
341
|
+
{
|
|
342
|
+
"id": "edge:email_1:email_2",
|
|
343
|
+
"source": "step:email_1",
|
|
344
|
+
"target": "step:email_2",
|
|
345
|
+
"kind": "next",
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
},
|
|
305
349
|
},
|
|
306
350
|
"linkedin_outreach": {
|
|
307
|
-
"name": "LinkedIn outreach
|
|
351
|
+
"name": "LinkedIn outreach flow",
|
|
308
352
|
"sourceTableId": "<TABLE_ID>",
|
|
309
353
|
"sourceTableName": "ICP Prospects",
|
|
310
354
|
"exitRules": {
|
|
@@ -342,10 +386,24 @@ SEQUENCE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
|
342
386
|
"aiDraft": True,
|
|
343
387
|
"scriptTemplate": "",
|
|
344
388
|
},
|
|
389
|
+
{
|
|
390
|
+
"id": "email_fallback_1",
|
|
391
|
+
"kind": "EMAIL",
|
|
392
|
+
"waitDays": 0,
|
|
393
|
+
"waitHours": 0,
|
|
394
|
+
"waitMinutes": 0,
|
|
395
|
+
"executionMode": "AUTOMATED",
|
|
396
|
+
"emailSendMode": "AUTOMATED",
|
|
397
|
+
"emailIsReply": False,
|
|
398
|
+
"appendSignature": True,
|
|
399
|
+
"aiDraft": True,
|
|
400
|
+
"subjectTemplate": "",
|
|
401
|
+
"bodyTemplate": "",
|
|
402
|
+
},
|
|
345
403
|
{
|
|
346
404
|
"id": "message_1",
|
|
347
405
|
"kind": "LINKEDIN_CHAT_MESSAGE",
|
|
348
|
-
"waitDays":
|
|
406
|
+
"waitDays": 0,
|
|
349
407
|
"waitHours": 0,
|
|
350
408
|
"waitMinutes": 0,
|
|
351
409
|
"executionMode": "AUTOMATED",
|
|
@@ -353,6 +411,110 @@ SEQUENCE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
|
353
411
|
"scriptTemplate": "",
|
|
354
412
|
},
|
|
355
413
|
],
|
|
414
|
+
"flowGraph": {
|
|
415
|
+
"version": 1,
|
|
416
|
+
"nodes": [
|
|
417
|
+
{
|
|
418
|
+
"id": "step:visit_1",
|
|
419
|
+
"kind": "action",
|
|
420
|
+
"title": "Visit profile",
|
|
421
|
+
"sourceStepId": "visit_1",
|
|
422
|
+
"position": {"x": 0, "y": 0},
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"id": "step:connect_1",
|
|
426
|
+
"kind": "action",
|
|
427
|
+
"title": "Connect",
|
|
428
|
+
"sourceStepId": "connect_1",
|
|
429
|
+
"position": {"x": 0, "y": 160},
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
"id": "condition:connect_1:accepted",
|
|
433
|
+
"kind": "condition",
|
|
434
|
+
"title": "Wait for connection accepted",
|
|
435
|
+
"parentNodeId": "step:connect_1",
|
|
436
|
+
"metadata": {
|
|
437
|
+
"decisionType": "outcome_wait",
|
|
438
|
+
"listenFor": "linkedin_connection_accepted",
|
|
439
|
+
"waitMode": "up_to",
|
|
440
|
+
"waitDays": 7,
|
|
441
|
+
"waitHours": 0,
|
|
442
|
+
"waitMinutes": 0,
|
|
443
|
+
},
|
|
444
|
+
"position": {"x": 0, "y": 320},
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"id": "branch:connect_1:accepted",
|
|
448
|
+
"kind": "branch",
|
|
449
|
+
"branchId": "connected",
|
|
450
|
+
"title": "Connected",
|
|
451
|
+
"parentNodeId": "condition:connect_1:accepted",
|
|
452
|
+
"position": {"x": -180, "y": 480},
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
"id": "branch:connect_1:timeout",
|
|
456
|
+
"kind": "branch",
|
|
457
|
+
"branchId": "not-connected",
|
|
458
|
+
"title": "Not connected after 7 days",
|
|
459
|
+
"parentNodeId": "condition:connect_1:accepted",
|
|
460
|
+
"position": {"x": 180, "y": 480},
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"id": "step:message_1",
|
|
464
|
+
"kind": "action",
|
|
465
|
+
"title": "LinkedIn message",
|
|
466
|
+
"parentNodeId": "branch:connect_1:accepted",
|
|
467
|
+
"sourceStepId": "message_1",
|
|
468
|
+
"position": {"x": -180, "y": 640},
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
"id": "step:email_fallback_1",
|
|
472
|
+
"kind": "action",
|
|
473
|
+
"title": "Fallback email",
|
|
474
|
+
"parentNodeId": "branch:connect_1:timeout",
|
|
475
|
+
"sourceStepId": "email_fallback_1",
|
|
476
|
+
"position": {"x": 180, "y": 640},
|
|
477
|
+
},
|
|
478
|
+
],
|
|
479
|
+
"edges": [
|
|
480
|
+
{
|
|
481
|
+
"id": "edge:visit_1:connect_1",
|
|
482
|
+
"source": "step:visit_1",
|
|
483
|
+
"target": "step:connect_1",
|
|
484
|
+
"kind": "next",
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
"id": "edge:connect_1:accepted_condition",
|
|
488
|
+
"source": "step:connect_1",
|
|
489
|
+
"target": "condition:connect_1:accepted",
|
|
490
|
+
"kind": "condition",
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
"id": "edge:accepted_condition:connected",
|
|
494
|
+
"source": "condition:connect_1:accepted",
|
|
495
|
+
"target": "branch:connect_1:accepted",
|
|
496
|
+
"kind": "branch",
|
|
497
|
+
},
|
|
498
|
+
{
|
|
499
|
+
"id": "edge:accepted_condition:timeout",
|
|
500
|
+
"source": "condition:connect_1:accepted",
|
|
501
|
+
"target": "branch:connect_1:timeout",
|
|
502
|
+
"kind": "branch",
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"id": "edge:connected:message_1",
|
|
506
|
+
"source": "branch:connect_1:accepted",
|
|
507
|
+
"target": "step:message_1",
|
|
508
|
+
"kind": "branch",
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
"id": "edge:timeout:email_fallback_1",
|
|
512
|
+
"source": "branch:connect_1:timeout",
|
|
513
|
+
"target": "step:email_fallback_1",
|
|
514
|
+
"kind": "branch",
|
|
515
|
+
},
|
|
516
|
+
],
|
|
517
|
+
},
|
|
356
518
|
},
|
|
357
519
|
"enroll": {
|
|
358
520
|
"leadIds": ["<LEAD_ID_1>", "<LEAD_ID_2>"],
|
|
@@ -365,25 +527,28 @@ SEQUENCE_RECIPES: Dict[str, Dict[str, Any]] = {
|
|
|
365
527
|
|
|
366
528
|
SEQUENCE_RECIPE_NOTES: Dict[str, List[str]] = {
|
|
367
529
|
"create": [
|
|
368
|
-
"Recommended default: personal delivery plus AUTOMATED email with aiDraft=true.",
|
|
530
|
+
"Recommended default: V2 flowGraph with personal delivery plus AUTOMATED email with aiDraft=true.",
|
|
531
|
+
"flowGraph.version=1 is the executable authoring layer; keep steps aligned with graph action sourceStepId values.",
|
|
369
532
|
"AI draft generates subject + body at execution time.",
|
|
370
|
-
"AI draft for
|
|
533
|
+
"AI draft for call generates a call script.",
|
|
371
534
|
"External sequence create/update requires sourceTableId.",
|
|
372
535
|
"Pass --actor-user-id on mutating commands when you need explicit actor resolution.",
|
|
373
536
|
],
|
|
374
537
|
"bulk_automated": [
|
|
538
|
+
"Emits a V2 flowGraph with two automated email actions.",
|
|
375
539
|
"Use this when the provider should send email automatically at scale.",
|
|
376
540
|
"Bulk delivery sequences cannot contain MANUAL email steps, so aiDraft does not apply to those email steps.",
|
|
377
541
|
"Activate only after provider readiness is configured (autotouch sequences delivery-status).",
|
|
378
542
|
],
|
|
379
543
|
"linkedin_outreach": [
|
|
380
|
-
"
|
|
544
|
+
"Emits a V2 flowGraph: visit profile, connect, wait for accepted connection, then branch to LinkedIn message or fallback email.",
|
|
381
545
|
"Supported step kinds: LINKEDIN_VISIT_PROFILE, LINKEDIN_CONNECT, LINKEDIN_CHAT_MESSAGE, LINKEDIN_VOICE_MESSAGE.",
|
|
382
546
|
"LINKEDIN_VISIT_PROFILE is always AUTOMATED and visits the lead's profile (notifies by default).",
|
|
383
547
|
"LINKEDIN_CONNECT sends a connection request; scriptTemplate is the invite note (max 300 chars).",
|
|
384
548
|
"LINKEDIN_CHAT_MESSAGE sends a direct message; uses InMail credits for 2nd/3rd degree connections.",
|
|
385
549
|
"LINKEDIN_VOICE_MESSAGE sends a voice note; only works for 1st degree connections.",
|
|
386
550
|
"Connection degree (1st/2nd/3rd/out_of_network) is auto-detected from the LinkedIn profile.",
|
|
551
|
+
"The connected branch is explicit in flowGraph; the fallback email branch is explicit and does not happen silently.",
|
|
387
552
|
"Set stopOnLinkedInReply=true in exitRules to stop the sequence when the lead replies on LinkedIn.",
|
|
388
553
|
"Leads must have a linkedin_url field to be reachable for LinkedIn steps.",
|
|
389
554
|
],
|
|
@@ -1787,6 +1952,7 @@ def emit_sequences_recipe(args: argparse.Namespace, runtime: TemplateRuntime) ->
|
|
|
1787
1952
|
usage_lookup={
|
|
1788
1953
|
"create": "autotouch sequences create --data-file <payload.json>",
|
|
1789
1954
|
"bulk_automated": "autotouch sequences create --data-file <payload.json>",
|
|
1955
|
+
"linkedin_outreach": "autotouch sequences create --data-file <payload.json>",
|
|
1790
1956
|
"enroll": "autotouch sequences enroll --sequence-id <SEQUENCE_ID> --data-file <payload.json>",
|
|
1791
1957
|
},
|
|
1792
1958
|
label="recipe",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: autotouch-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.90
|
|
4
4
|
Summary: Autotouch Smart Table CLI
|
|
5
5
|
Project-URL: Homepage, https://app.autotouch.ai
|
|
6
6
|
Project-URL: Documentation, https://github.com/nicolonic/autotouch_main/tree/main/docs/research-table/reference
|
|
@@ -36,6 +36,8 @@ For a shipped human-readable reference generated from the installed parser, use
|
|
|
36
36
|
|
|
37
37
|
## Install
|
|
38
38
|
|
|
39
|
+
Released package:
|
|
40
|
+
|
|
39
41
|
```bash
|
|
40
42
|
pipx install autotouch-cli
|
|
41
43
|
# or
|
|
@@ -44,6 +46,16 @@ pip install autotouch-cli
|
|
|
44
46
|
pip install -U autotouch-cli
|
|
45
47
|
```
|
|
46
48
|
|
|
49
|
+
Unreleased branch or pre-publish build:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pipx install --force "git+ssh://git@github.com/nicolonic/autotouch_main.git@<branch-or-sha>"
|
|
53
|
+
# or
|
|
54
|
+
python -m pip install -U "git+ssh://git@github.com/nicolonic/autotouch_main.git@<branch-or-sha>"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The `autotouch-cli` package name installs the latest published package from the configured package index. Use the git/source install form when testing a version bump before the release tag has published.
|
|
58
|
+
|
|
47
59
|
## First Run
|
|
48
60
|
|
|
49
61
|
Existing developer key:
|
|
@@ -158,13 +170,15 @@ For structured company builds, start with industry IDs plus geo/company-size fil
|
|
|
158
170
|
|
|
159
171
|
For account-first prospecting from LinkedIn/Sales Navigator, build companies/accounts first, inspect the returned company IDs, then pass those IDs to `autotouch list-build leads --current-company-id ...`. Do not use Exa company search as a default pre-step for every LinkedIn list build; use it when the user's target is genuinely semantic, niche, competitor-based, or not meant to be LinkedIn-sourced.
|
|
160
172
|
|
|
173
|
+
Use `autotouch agents ...` for recurring signal-based discovery. Scheduled agents support `--target ACCOUNTS` for company/account output and `--target LEADS` for people output. Every agent writes a source/signal table for the evidence it used; lead agents then write `candidate_research.candidates[]` on source rows and list-sync those candidates into the lead/candidate output table. See the agent playbook for the full source-table and candidate-sync contract.
|
|
174
|
+
|
|
161
175
|
## More
|
|
162
176
|
|
|
163
177
|
For automation or agent-driven setup, use:
|
|
164
178
|
- `autotouch cli-manifest --output json` for the local machine-readable command contract
|
|
165
179
|
- `autotouch cli-reference` for the shipped parser-generated reference
|
|
166
180
|
- `autotouch capabilities --output json` for provider/workflow contracts
|
|
167
|
-
- `autotouch --version` should be `0.2.
|
|
181
|
+
- `autotouch --version` should be `0.2.90` or newer for structured company list builds without user-supplied keywords, stored list-build input lookup, research-workspace list-build guidance, the cleaned single LinkedIn-sourced list-build path, Exa Company Search up to 100 results, scheduled agent `--target ACCOUNTS|LEADS`, paced HTTP Request column contracts, and V2 sequence flowGraph recipes
|
|
168
182
|
- `autotouch capabilities --output json --select list_builds` for documented list-build inputs such as geography IDs, company size buckets, profile language, and company IDs
|
|
169
183
|
- `autotouch list-build inputs` and `autotouch list-build pricing` before creating durable list-build jobs
|
|
170
184
|
- `autotouch list-build companies` and `autotouch list-build leads` for durable LinkedIn-sourced company and lead list builds with Smart Table-owned background workers, visible progress, and no user-owned LinkedIn connection requirement
|
|
@@ -1089,12 +1089,20 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
|
|
|
1089
1089
|
"headers": {},
|
|
1090
1090
|
"body": None,
|
|
1091
1091
|
"timeoutSeconds": 30,
|
|
1092
|
+
"rateLimit": {
|
|
1093
|
+
"enabled": False,
|
|
1094
|
+
"minDelayMs": 5000,
|
|
1095
|
+
"jitterMs": 1000,
|
|
1096
|
+
"maxConcurrency": 1,
|
|
1097
|
+
"scope": "credential",
|
|
1098
|
+
},
|
|
1092
1099
|
},
|
|
1093
1100
|
},
|
|
1094
1101
|
recipe_notes=(
|
|
1095
1102
|
"Use {{column_key}} placeholders in config.url, config.headers, and config.body to reference row values.",
|
|
1096
1103
|
"Use {{secrets.name}} to resolve a workspace secret by name.",
|
|
1097
1104
|
"body can be null, a string template, or an object whose values are templated and sent as JSON.",
|
|
1105
|
+
"Set config.rateLimit.enabled=true for paced background execution. The current safe mode is maxConcurrency=1 with minDelayMs/jitterMs spacing, coordinated across workers by organization, host, and scope.",
|
|
1098
1106
|
"The stored cell value is the parsed response body (JSON or text), not the full transport envelope.",
|
|
1099
1107
|
"Preview the resolved request with `autotouch columns test-http-request --table-id <TABLE_ID> --data-file column.json` before creating or running the column.",
|
|
1100
1108
|
),
|
|
@@ -1123,6 +1131,15 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
|
|
|
1123
1131
|
"headers_field": "config.headers",
|
|
1124
1132
|
"body_field": "config.body",
|
|
1125
1133
|
"timeout_field": "config.timeoutSeconds",
|
|
1134
|
+
"rate_limit": {
|
|
1135
|
+
"field": "config.rateLimit",
|
|
1136
|
+
"enabled": "optional boolean",
|
|
1137
|
+
"minDelayMs": "optional integer milliseconds between worker requests",
|
|
1138
|
+
"jitterMs": "optional integer random extra delay in milliseconds",
|
|
1139
|
+
"maxConcurrency": "currently only 1 is supported for strict serialized pacing",
|
|
1140
|
+
"scope": "credential | host | column",
|
|
1141
|
+
"credential_scope": "organization + resolved host + referenced {{secrets.name}} names; falls back to column id when no secrets are referenced",
|
|
1142
|
+
},
|
|
1126
1143
|
"supported_methods": list(_HTTP_REQUEST_METHODS),
|
|
1127
1144
|
"template_syntax": {
|
|
1128
1145
|
"row_values": "{{column_key}}",
|
|
@@ -1564,6 +1581,34 @@ def validate_column_provider_contract(
|
|
|
1564
1581
|
"http_request config.body must be null, a string, or an object.",
|
|
1565
1582
|
hint="Use a string body template or a JSON object whose values contain {{column_key}} placeholders.",
|
|
1566
1583
|
)
|
|
1584
|
+
rate_limit = cfg.get("rateLimit") or cfg.get("rate_limit")
|
|
1585
|
+
if rate_limit is not None:
|
|
1586
|
+
if not isinstance(rate_limit, dict):
|
|
1587
|
+
raise ProviderContractValidationError(
|
|
1588
|
+
"invalid_field",
|
|
1589
|
+
"http_request config.rateLimit must be an object when provided.",
|
|
1590
|
+
hint="Use {\"enabled\": true, \"minDelayMs\": 5000, \"jitterMs\": 1000, \"maxConcurrency\": 1, \"scope\": \"credential\"}.",
|
|
1591
|
+
)
|
|
1592
|
+
max_concurrency = rate_limit.get("maxConcurrency", rate_limit.get("max_concurrency", 1))
|
|
1593
|
+
try:
|
|
1594
|
+
parsed_max_concurrency = int(float(max_concurrency))
|
|
1595
|
+
except (TypeError, ValueError):
|
|
1596
|
+
parsed_max_concurrency = 1
|
|
1597
|
+
if parsed_max_concurrency != 1:
|
|
1598
|
+
raise ProviderContractValidationError(
|
|
1599
|
+
"invalid_field",
|
|
1600
|
+
"http_request config.rateLimit.maxConcurrency currently supports only 1.",
|
|
1601
|
+
hint="Use maxConcurrency: 1 for serialized paced requests.",
|
|
1602
|
+
detail={"maxConcurrency": max_concurrency},
|
|
1603
|
+
)
|
|
1604
|
+
scope = str(rate_limit.get("scope") or "credential").strip().lower()
|
|
1605
|
+
if scope not in {"credential", "host", "column"}:
|
|
1606
|
+
raise ProviderContractValidationError(
|
|
1607
|
+
"invalid_field",
|
|
1608
|
+
"http_request config.rateLimit.scope must be credential, host, or column.",
|
|
1609
|
+
hint="Use scope: \"credential\" for API keys, cookies, and session-backed providers.",
|
|
1610
|
+
detail={"scope": rate_limit.get("scope")},
|
|
1611
|
+
)
|
|
1567
1612
|
return contract
|
|
1568
1613
|
|
|
1569
1614
|
return contract
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|