autotouch-cli 0.2.46__tar.gz → 0.2.48__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.
Files changed (46) hide show
  1. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/PKG-INFO +14 -5
  2. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/README.md +13 -4
  3. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/cli.py +12 -4
  4. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/auth.py +9 -8
  5. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/cells.py +5 -1
  6. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/columns.py +13 -4
  7. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/data/CLI_REFERENCE.md +20 -9
  8. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/data/cli-manifest.json +77 -14
  9. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/templates.py +6 -3
  10. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli.egg-info/PKG-INFO +14 -5
  11. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_shared/provider_registry.py +97 -7
  12. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/pyproject.toml +1 -1
  13. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/MANIFEST.in +0 -0
  14. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/__init__.py +0 -0
  15. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/cli_contracts.py +0 -0
  16. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/__init__.py +0 -0
  17. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/jobs.py +0 -0
  18. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/leads.py +0 -0
  19. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/linkedin.py +0 -0
  20. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/prompts.py +0 -0
  21. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/rows.py +0 -0
  22. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/search.py +0 -0
  23. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/sequences.py +0 -0
  24. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/tables.py +0 -0
  25. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/tasks.py +0 -0
  26. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/webhooks.py +0 -0
  27. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/commands/workspace_secrets.py +0 -0
  28. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/__init__.py +0 -0
  29. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/auth.py +0 -0
  30. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/config.py +0 -0
  31. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/http.py +0 -0
  32. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/io.py +0 -0
  33. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/output.py +0 -0
  34. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/core/polling.py +0 -0
  35. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/mongo_status.py +0 -0
  36. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/parser_groups.py +0 -0
  37. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli/sequence_support.py +0 -0
  38. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli.egg-info/SOURCES.txt +0 -0
  39. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli.egg-info/dependency_links.txt +0 -0
  40. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli.egg-info/entry_points.txt +0 -0
  41. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli.egg-info/requires.txt +0 -0
  42. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_cli.egg-info/top_level.txt +0 -0
  43. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_shared/__init__.py +0 -0
  44. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_shared/linkedin_contract.py +0 -0
  45. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/autotouch_shared/search_contract.py +0 -0
  46. {autotouch_cli-0.2.46 → autotouch_cli-0.2.48}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.46
3
+ Version: 0.2.48
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
@@ -146,9 +146,18 @@ For automation or agent-driven setup, use:
146
146
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
147
147
  - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
148
148
 
149
+ ## LLM Columns
150
+
151
+ For `llm_enrichment` in `agent` mode, the recommended path is:
152
+ - provide `config.instructions`
153
+ - let the API compile the runnable prompt
154
+ - keep `config.useAutoSchema = true`
155
+
156
+ Only send `user_schema` / `response_schema` when you intentionally want to override the generated schema and keep it aligned yourself. The installed recipe surface at `autotouch columns recipe --type llm_enrichment` follows this contract.
157
+
149
158
  ## Docs
150
159
 
151
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/autotouch-cli.md
152
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/guides/autotouch-cli-agent-playbook.md
153
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/tables-api.md
154
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/platform/authentication.md
160
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/autotouch-cli.md
161
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/guides/autotouch-cli-agent-playbook.md
162
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/tables-api.md
163
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/platform/authentication.md
@@ -121,9 +121,18 @@ For automation or agent-driven setup, use:
121
121
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
122
122
  - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
123
123
 
124
+ ## LLM Columns
125
+
126
+ For `llm_enrichment` in `agent` mode, the recommended path is:
127
+ - provide `config.instructions`
128
+ - let the API compile the runnable prompt
129
+ - keep `config.useAutoSchema = true`
130
+
131
+ Only send `user_schema` / `response_schema` when you intentionally want to override the generated schema and keep it aligned yourself. The installed recipe surface at `autotouch columns recipe --type llm_enrichment` follows this contract.
132
+
124
133
  ## Docs
125
134
 
126
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/autotouch-cli.md
127
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/guides/autotouch-cli-agent-playbook.md
128
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/tables-api.md
129
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/platform/authentication.md
135
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/autotouch-cli.md
136
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/guides/autotouch-cli-agent-playbook.md
137
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/tables-api.md
138
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/platform/authentication.md
@@ -1091,8 +1091,7 @@ def _normalize_run_payload(args: argparse.Namespace) -> Dict[str, Any]:
1091
1091
  if filters is not None:
1092
1092
  payload["filters"] = filters
1093
1093
 
1094
- if getattr(args, "unprocessed_only", False):
1095
- payload["unprocessedOnly"] = True
1094
+ payload["unprocessedOnly"] = bool(getattr(args, "unprocessed_only", True))
1096
1095
 
1097
1096
  return payload
1098
1097
 
@@ -3559,11 +3558,20 @@ def _add_run_scope_arguments(parser: argparse.ArgumentParser) -> None:
3559
3558
  type=int,
3560
3559
  help="First N rows (for scope=firstN). Use with --unprocessed-only to process the next rows without reruns",
3561
3560
  )
3562
- parser.add_argument(
3561
+ run_mode = parser.add_mutually_exclusive_group()
3562
+ run_mode.add_argument(
3563
3563
  "--unprocessed-only",
3564
+ dest="unprocessed_only",
3564
3565
  action="store_true",
3565
- help="Only process rows without values (recommended with scope=firstN)",
3566
+ help="Only process rows without values (default)",
3567
+ )
3568
+ run_mode.add_argument(
3569
+ "--include-processed",
3570
+ dest="unprocessed_only",
3571
+ action="store_false",
3572
+ help="Include rows that already have output",
3566
3573
  )
3574
+ parser.set_defaults(unprocessed_only=True)
3567
3575
  parser.add_argument("--filters-json", help="JSON object for scope=filtered")
3568
3576
  parser.add_argument("--filters-file", help="Path to JSON file for scope=filtered")
3569
3577
  parser.add_argument("--data-json", help="Explicit RunRequest payload JSON (overrides scope flags)")
@@ -30,19 +30,16 @@ def cmd_auth_check(args: argparse.Namespace, *, runtime: AuthCommandRuntime) ->
30
30
  token = runtime.resolve_token(args.token, required=True)
31
31
  body = runtime.request_api(
32
32
  "GET",
33
- "/api/capabilities",
33
+ "/api/auth/check",
34
34
  base_url=args.base_url,
35
35
  token=token,
36
36
  use_x_api_key=args.use_x_api_key,
37
37
  timeout=args.timeout,
38
38
  verbose=args.verbose,
39
39
  )
40
- output = {
41
- "ok": True,
42
- "base_url": runtime.api_url(args.base_url),
43
- "api_version": body.get("api_version") if isinstance(body, dict) else None,
44
- "auth_header_mode": "x-api-key" if args.use_x_api_key else "authorization",
45
- }
40
+ output = dict(body) if isinstance(body, dict) else {"ok": True}
41
+ output["base_url"] = runtime.api_url(args.base_url)
42
+ output["auth_header_mode"] = "x-api-key" if args.use_x_api_key else "authorization"
46
43
  runtime.print_json(output, args.compact)
47
44
 
48
45
 
@@ -363,7 +360,11 @@ def register_auth_subcommands(
363
360
  auth = subparsers.add_parser("auth", help="Auth helpers")
364
361
  auth_sub = auth.add_subparsers(dest="auth_cmd", required=True)
365
362
 
366
- pa = auth_sub.add_parser("check", help="Validate token against /api/capabilities")
363
+ pa = auth_sub.add_parser(
364
+ "check",
365
+ help="Validate the current token/session and show granted scopes",
366
+ description="Validate the current token/session against the API and show granted scopes for developer API keys.",
367
+ )
367
368
  add_api_common_arguments(pa)
368
369
  pa.set_defaults(func=handlers["check"])
369
370
 
@@ -85,7 +85,11 @@ def register_cells_subcommands(
85
85
  add_api_common_arguments(get_parser)
86
86
  get_parser.set_defaults(func=handlers["get"])
87
87
 
88
- patch_parser = cells_sub.add_parser("patch", help="Patch cells in batch")
88
+ patch_parser = cells_sub.add_parser(
89
+ "patch",
90
+ help="Patch cells in batch",
91
+ description="Patch cells in batch. Use column key strings in updates[].key; this payload does not accept columnId.",
92
+ )
89
93
  patch_parser.add_argument("--table-id", required=True)
90
94
  patch_parser.add_argument("--updates-json", help="JSON list or {updates:[...]} object")
91
95
  patch_parser.add_argument("--updates-file", help="Path to JSON file with updates payload")
@@ -273,9 +273,11 @@ def cmd_columns_run_next(args: argparse.Namespace, *, runtime: ColumnCommandRunt
273
273
  sys.exit(3)
274
274
  return
275
275
 
276
- payload: Dict[str, Any] = {"scope": "subset", "rowIds": row_ids}
277
- if args.unprocessed_only:
278
- payload["unprocessedOnly"] = True
276
+ payload: Dict[str, Any] = {
277
+ "scope": "subset",
278
+ "rowIds": row_ids,
279
+ "unprocessedOnly": bool(args.unprocessed_only),
280
+ }
279
281
 
280
282
  context = {
281
283
  "mode": "run-next",
@@ -327,7 +329,14 @@ def register_columns_subcommands(
327
329
  add_api_common_arguments(pcc)
328
330
  pcc.set_defaults(func=handlers["create"])
329
331
 
330
- pcu = col_sub.add_parser("update", help="Update a column")
332
+ pcu = col_sub.add_parser(
333
+ "update",
334
+ help="Update a column",
335
+ description=(
336
+ "Update a column definition. Nested config keys merge into the existing config, "
337
+ "so partial config patches are supported."
338
+ ),
339
+ )
331
340
  pcu.add_argument("--table-id", required=True)
332
341
  pcu.add_argument("--column-id", required=True)
333
342
  pcu.add_argument("--data-json", help="ColumnUpdate payload JSON")
@@ -1,6 +1,6 @@
1
1
  # Autotouch CLI Reference
2
2
 
3
- Generated from the installed parser for `autotouch-cli` `0.2.46`.
3
+ Generated from the installed parser for `autotouch-cli` `0.2.48`.
4
4
  Manifest schema version: `2`.
5
5
 
6
6
  ## Output Modes
@@ -71,7 +71,9 @@ Register an account/org and return a developer key
71
71
 
72
72
  #### `autotouch auth check`
73
73
 
74
- Validate token against /api/capabilities
74
+ Validate the current token/session and show granted scopes
75
+
76
+ Validate the current token/session against the API and show granted scopes for developer API keys.
75
77
 
76
78
  - Auth: `developer_key_or_user_session`
77
79
  - Stability: `stable`
@@ -505,6 +507,8 @@ Get one cell with value/status/metadata
505
507
 
506
508
  Patch cells in batch
507
509
 
510
+ Patch cells in batch. Use column key strings in updates[].key; this payload does not accept columnId.
511
+
508
512
  - Auth: `developer_key_or_user_session`
509
513
  - Stability: `stable`
510
514
  - Destructive: `no`
@@ -691,7 +695,8 @@ Estimate a column run
691
695
  --column-id COLUMN_ID
692
696
  [--scope {all,subset,row,firstN,filtered}]
693
697
  [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]
694
- [--first-n FIRST_N] [--unprocessed-only]
698
+ [--first-n FIRST_N] [--unprocessed-only |
699
+ --include-processed]
695
700
  [--filters-json FILTERS_JSON]
696
701
  [--filters-file FILTERS_FILE]
697
702
  [--data-json DATA_JSON]
@@ -708,7 +713,8 @@ Estimate a column run
708
713
  - `--row-id` (kind=string): Single row ID for scope=row
709
714
  - `--row-ids` (kind=list): Row IDs for subset scope (or a single row when scope=row)
710
715
  - `--first-n` (kind=integer): First N rows (for scope=firstN). Use with --unprocessed-only to process the next rows without reruns
711
- - `--unprocessed-only` (kind=boolean; when omitted=False; when present=True): Only process rows without values (recommended with scope=firstN)
716
+ - `--unprocessed-only` (kind=boolean; when omitted=True; when present=True): Only process rows without values (default)
717
+ - `--include-processed` (kind=boolean; when omitted=True; when present=False): Include rows that already have output
712
718
  - `--filters-json` (kind=json; input=json): JSON object for scope=filtered
713
719
  - `--filters-file` (kind=file; input=file): Path to JSON file for scope=filtered
714
720
  - `--data-json` (kind=json; input=json): Explicit RunRequest payload JSON (overrides scope flags)
@@ -842,7 +848,8 @@ Run a column
842
848
  - `autotouch columns run [-h] --table-id TABLE_ID --column-id COLUMN_ID
843
849
  [--scope {all,subset,row,firstN,filtered}]
844
850
  [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]
845
- [--first-n FIRST_N] [--unprocessed-only]
851
+ [--first-n FIRST_N] [--unprocessed-only |
852
+ --include-processed]
846
853
  [--filters-json FILTERS_JSON]
847
854
  [--filters-file FILTERS_FILE]
848
855
  [--data-json DATA_JSON] [--data-file DATA_FILE]
@@ -864,7 +871,8 @@ Run a column
864
871
  - `--row-id` (kind=string): Single row ID for scope=row
865
872
  - `--row-ids` (kind=list): Row IDs for subset scope (or a single row when scope=row)
866
873
  - `--first-n` (kind=integer): First N rows (for scope=firstN). Use with --unprocessed-only to process the next rows without reruns
867
- - `--unprocessed-only` (kind=boolean; when omitted=False; when present=True): Only process rows without values (recommended with scope=firstN)
874
+ - `--unprocessed-only` (kind=boolean; when omitted=True; when present=True): Only process rows without values (default)
875
+ - `--include-processed` (kind=boolean; when omitted=True; when present=False): Include rows that already have output
868
876
  - `--filters-json` (kind=json; input=json): JSON object for scope=filtered
869
877
  - `--filters-file` (kind=file; input=file): Path to JSON file for scope=filtered
870
878
  - `--data-json` (kind=json; input=json): Explicit RunRequest payload JSON (overrides scope flags)
@@ -1021,6 +1029,8 @@ Template syntax:
1021
1029
 
1022
1030
  Update a column
1023
1031
 
1032
+ Update a column definition. Nested config keys merge into the existing config, so partial config patches are supported.
1033
+
1024
1034
  - Auth: `developer_key_or_user_session`
1025
1035
  - Stability: `stable`
1026
1036
  - Destructive: `no`
@@ -2845,8 +2855,8 @@ Alias for: columns run
2845
2855
  - `autotouch run [-h] --table-id TABLE_ID --column-id COLUMN_ID
2846
2856
  [--scope {all,subset,row,firstN,filtered}]
2847
2857
  [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]
2848
- [--first-n FIRST_N] [--unprocessed-only]
2849
- [--filters-json FILTERS_JSON]
2858
+ [--first-n FIRST_N] [--unprocessed-only |
2859
+ --include-processed] [--filters-json FILTERS_JSON]
2850
2860
  [--filters-file FILTERS_FILE] [--data-json DATA_JSON]
2851
2861
  [--data-file DATA_FILE] [--show-estimate] [--dry-run]
2852
2862
  [--max-credits MAX_CREDITS] [--allow-unknown-max]
@@ -2864,7 +2874,8 @@ Alias for: columns run
2864
2874
  - `--row-id` (kind=string): Single row ID for scope=row
2865
2875
  - `--row-ids` (kind=list): Row IDs for subset scope (or a single row when scope=row)
2866
2876
  - `--first-n` (kind=integer): First N rows (for scope=firstN). Use with --unprocessed-only to process the next rows without reruns
2867
- - `--unprocessed-only` (kind=boolean; when omitted=False; when present=True): Only process rows without values (recommended with scope=firstN)
2877
+ - `--unprocessed-only` (kind=boolean; when omitted=True; when present=True): Only process rows without values (default)
2878
+ - `--include-processed` (kind=boolean; when omitted=True; when present=False): Include rows that already have output
2868
2879
  - `--filters-json` (kind=json; input=json): JSON object for scope=filtered
2869
2880
  - `--filters-file` (kind=file; input=file): Path to JSON file for scope=filtered
2870
2881
  - `--data-json` (kind=json; input=json): Explicit RunRequest payload JSON (overrides scope flags)
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.46",
2
+ "version": "0.2.48",
3
3
  "manifest_schema_version": 2,
4
4
  "entry_points": {
5
5
  "autotouch": "autotouch_cli.cli:main",
@@ -653,8 +653,8 @@
653
653
  ],
654
654
  "aliases": [],
655
655
  "group": "auth",
656
- "help": "Validate token against /api/capabilities",
657
- "description": null,
656
+ "help": "Validate the current token/session and show granted scopes",
657
+ "description": "Validate the current token/session against the API and show granted scopes for developer API keys.",
658
658
  "notes": null,
659
659
  "required_flags": [],
660
660
  "positionals": [],
@@ -12613,7 +12613,7 @@
12613
12613
  "aliases": [],
12614
12614
  "group": "cells",
12615
12615
  "help": "Patch cells in batch",
12616
- "description": null,
12616
+ "description": "Patch cells in batch. Use column key strings in updates[].key; this payload does not accept columnId.",
12617
12617
  "notes": null,
12618
12618
  "required_flags": [
12619
12619
  "--table-id"
@@ -13403,7 +13403,7 @@
13403
13403
  "aliases": [],
13404
13404
  "group": "columns",
13405
13405
  "help": "Update a column",
13406
- "description": null,
13406
+ "description": "Update a column definition. Nested config keys merge into the existing config, so partial config patches are supported.",
13407
13407
  "notes": null,
13408
13408
  "required_flags": [
13409
13409
  "--table-id",
@@ -14340,17 +14340,31 @@
14340
14340
  {
14341
14341
  "dest": "unprocessed_only",
14342
14342
  "required": false,
14343
- "help": "Only process rows without values (recommended with scope=firstN)",
14343
+ "help": "Only process rows without values (default)",
14344
14344
  "kind": "boolean",
14345
14345
  "action": "store_true",
14346
14346
  "nargs": 0,
14347
- "default_when_omitted": false,
14347
+ "default_when_omitted": true,
14348
14348
  "value_when_present": true,
14349
14349
  "flags": [
14350
14350
  "--unprocessed-only"
14351
14351
  ],
14352
14352
  "takes_value": false
14353
14353
  },
14354
+ {
14355
+ "dest": "unprocessed_only",
14356
+ "required": false,
14357
+ "help": "Include rows that already have output",
14358
+ "kind": "boolean",
14359
+ "action": "store_false",
14360
+ "nargs": 0,
14361
+ "default_when_omitted": true,
14362
+ "value_when_present": false,
14363
+ "flags": [
14364
+ "--include-processed"
14365
+ ],
14366
+ "takes_value": false
14367
+ },
14354
14368
  {
14355
14369
  "dest": "filters_json",
14356
14370
  "required": false,
@@ -14656,6 +14670,13 @@
14656
14670
  }
14657
14671
  ],
14658
14672
  "mutually_exclusive_groups": [
14673
+ {
14674
+ "required": false,
14675
+ "options": [
14676
+ "--unprocessed-only",
14677
+ "--include-processed"
14678
+ ]
14679
+ },
14659
14680
  {
14660
14681
  "required": false,
14661
14682
  "options": [
@@ -14688,7 +14709,7 @@
14688
14709
  },
14689
14710
  "availability": null,
14690
14711
  "examples": [
14691
- "autotouch columns run [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--scope {all,subset,row,firstN,filtered}]\n [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]\n [--first-n FIRST_N] [--unprocessed-only]\n [--filters-json FILTERS_JSON]\n [--filters-file FILTERS_FILE]\n [--data-json DATA_JSON] [--data-file DATA_FILE]\n [--show-estimate] [--dry-run]\n [--max-credits MAX_CREDITS] [--allow-unknown-max]\n [--wait] [--quiet-wait]\n [--poll-interval POLL_INTERVAL]\n [--wait-timeout WAIT_TIMEOUT] [--fail-on-error]\n [--fail-on-partial] [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT | --json-pointer JSON_POINTER]\n [--verbose]"
14712
+ "autotouch columns run [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--scope {all,subset,row,firstN,filtered}]\n [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]\n [--first-n FIRST_N] [--unprocessed-only |\n --include-processed]\n [--filters-json FILTERS_JSON]\n [--filters-file FILTERS_FILE]\n [--data-json DATA_JSON] [--data-file DATA_FILE]\n [--show-estimate] [--dry-run]\n [--max-credits MAX_CREDITS] [--allow-unknown-max]\n [--wait] [--quiet-wait]\n [--poll-interval POLL_INTERVAL]\n [--wait-timeout WAIT_TIMEOUT] [--fail-on-error]\n [--fail-on-partial] [--base-url BASE_URL]\n [--token TOKEN] [--use-x-api-key]\n [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT | --json-pointer JSON_POINTER]\n [--verbose]"
14692
14713
  ],
14693
14714
  "stability": "stable",
14694
14715
  "handler": "cmd_columns_run"
@@ -15396,17 +15417,31 @@
15396
15417
  {
15397
15418
  "dest": "unprocessed_only",
15398
15419
  "required": false,
15399
- "help": "Only process rows without values (recommended with scope=firstN)",
15420
+ "help": "Only process rows without values (default)",
15400
15421
  "kind": "boolean",
15401
15422
  "action": "store_true",
15402
15423
  "nargs": 0,
15403
- "default_when_omitted": false,
15424
+ "default_when_omitted": true,
15404
15425
  "value_when_present": true,
15405
15426
  "flags": [
15406
15427
  "--unprocessed-only"
15407
15428
  ],
15408
15429
  "takes_value": false
15409
15430
  },
15431
+ {
15432
+ "dest": "unprocessed_only",
15433
+ "required": false,
15434
+ "help": "Include rows that already have output",
15435
+ "kind": "boolean",
15436
+ "action": "store_false",
15437
+ "nargs": 0,
15438
+ "default_when_omitted": true,
15439
+ "value_when_present": false,
15440
+ "flags": [
15441
+ "--include-processed"
15442
+ ],
15443
+ "takes_value": false
15444
+ },
15410
15445
  {
15411
15446
  "dest": "filters_json",
15412
15447
  "required": false,
@@ -15577,6 +15612,13 @@
15577
15612
  }
15578
15613
  ],
15579
15614
  "mutually_exclusive_groups": [
15615
+ {
15616
+ "required": false,
15617
+ "options": [
15618
+ "--unprocessed-only",
15619
+ "--include-processed"
15620
+ ]
15621
+ },
15580
15622
  {
15581
15623
  "required": false,
15582
15624
  "options": [
@@ -15608,7 +15650,7 @@
15608
15650
  },
15609
15651
  "availability": null,
15610
15652
  "examples": [
15611
- "autotouch columns estimate [-h] --table-id TABLE_ID\n --column-id COLUMN_ID\n [--scope {all,subset,row,firstN,filtered}]\n [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]\n [--first-n FIRST_N] [--unprocessed-only]\n [--filters-json FILTERS_JSON]\n [--filters-file FILTERS_FILE]\n [--data-json DATA_JSON]\n [--data-file DATA_FILE]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
15653
+ "autotouch columns estimate [-h] --table-id TABLE_ID\n --column-id COLUMN_ID\n [--scope {all,subset,row,firstN,filtered}]\n [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]\n [--first-n FIRST_N] [--unprocessed-only |\n --include-processed]\n [--filters-json FILTERS_JSON]\n [--filters-file FILTERS_FILE]\n [--data-json DATA_JSON]\n [--data-file DATA_FILE]\n [--base-url BASE_URL] [--token TOKEN]\n [--use-x-api-key] [--timeout TIMEOUT]\n [--output {json,ndjson,human}] [--compact]\n [--select SELECT |\n --json-pointer JSON_POINTER] [--verbose]"
15612
15654
  ],
15613
15655
  "stability": "stable",
15614
15656
  "handler": "cmd_columns_estimate"
@@ -31080,17 +31122,31 @@
31080
31122
  {
31081
31123
  "dest": "unprocessed_only",
31082
31124
  "required": false,
31083
- "help": "Only process rows without values (recommended with scope=firstN)",
31125
+ "help": "Only process rows without values (default)",
31084
31126
  "kind": "boolean",
31085
31127
  "action": "store_true",
31086
31128
  "nargs": 0,
31087
- "default_when_omitted": false,
31129
+ "default_when_omitted": true,
31088
31130
  "value_when_present": true,
31089
31131
  "flags": [
31090
31132
  "--unprocessed-only"
31091
31133
  ],
31092
31134
  "takes_value": false
31093
31135
  },
31136
+ {
31137
+ "dest": "unprocessed_only",
31138
+ "required": false,
31139
+ "help": "Include rows that already have output",
31140
+ "kind": "boolean",
31141
+ "action": "store_false",
31142
+ "nargs": 0,
31143
+ "default_when_omitted": true,
31144
+ "value_when_present": false,
31145
+ "flags": [
31146
+ "--include-processed"
31147
+ ],
31148
+ "takes_value": false
31149
+ },
31094
31150
  {
31095
31151
  "dest": "filters_json",
31096
31152
  "required": false,
@@ -31396,6 +31452,13 @@
31396
31452
  }
31397
31453
  ],
31398
31454
  "mutually_exclusive_groups": [
31455
+ {
31456
+ "required": false,
31457
+ "options": [
31458
+ "--unprocessed-only",
31459
+ "--include-processed"
31460
+ ]
31461
+ },
31399
31462
  {
31400
31463
  "required": false,
31401
31464
  "options": [
@@ -31427,7 +31490,7 @@
31427
31490
  },
31428
31491
  "availability": null,
31429
31492
  "examples": [
31430
- "autotouch run [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--scope {all,subset,row,firstN,filtered}]\n [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]\n [--first-n FIRST_N] [--unprocessed-only]\n [--filters-json FILTERS_JSON]\n [--filters-file FILTERS_FILE] [--data-json DATA_JSON]\n [--data-file DATA_FILE] [--show-estimate] [--dry-run]\n [--max-credits MAX_CREDITS] [--allow-unknown-max]\n [--wait] [--quiet-wait] [--poll-interval POLL_INTERVAL]\n [--wait-timeout WAIT_TIMEOUT] [--fail-on-error]\n [--fail-on-partial] [--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]"
31493
+ "autotouch run [-h] --table-id TABLE_ID --column-id COLUMN_ID\n [--scope {all,subset,row,firstN,filtered}]\n [--row-id ROW_ID] [--row-ids [ROW_IDS ...]]\n [--first-n FIRST_N] [--unprocessed-only |\n --include-processed] [--filters-json FILTERS_JSON]\n [--filters-file FILTERS_FILE] [--data-json DATA_JSON]\n [--data-file DATA_FILE] [--show-estimate] [--dry-run]\n [--max-credits MAX_CREDITS] [--allow-unknown-max]\n [--wait] [--quiet-wait] [--poll-interval POLL_INTERVAL]\n [--wait-timeout WAIT_TIMEOUT] [--fail-on-error]\n [--fail-on-partial] [--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]"
31431
31494
  ],
31432
31495
  "stability": "stable",
31433
31496
  "handler": "cmd_columns_run"
@@ -665,13 +665,16 @@ CELL_SCHEMA_TYPES = ["patch_updates"]
665
665
  CELL_SCHEMAS = {
666
666
  "patch_updates": {
667
667
  "updates": [
668
- {"rowId": "<ROW_ID>", "columnId": "<COLUMN_ID>", "value": "New value"},
669
- {"rowId": "<ROW_ID_2>", "columnId": "<COLUMN_ID>", "value": 42},
668
+ {"rowId": "<ROW_ID>", "key": "status", "value": "New value"},
669
+ {"rowId": "<ROW_ID_2>", "key": "score", "value": 42},
670
670
  ]
671
671
  }
672
672
  }
673
673
  CELL_SCHEMA_NOTES = {
674
- "patch_updates": ["cells patch accepts a bare list too; this schema uses the explicit updates[] wrapper."],
674
+ "patch_updates": [
675
+ "cells patch accepts a bare list too; this schema uses the explicit updates[] wrapper.",
676
+ "Use column key strings in updates[].key; the API does not accept columnId here.",
677
+ ],
675
678
  }
676
679
 
677
680
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: autotouch-cli
3
- Version: 0.2.46
3
+ Version: 0.2.48
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
@@ -146,9 +146,18 @@ For automation or agent-driven setup, use:
146
146
  - `autotouch sequences ...` and `autotouch tasks ...` for sequence/task workflows
147
147
  - `pip install 'autotouch-cli[mongo]'` if you need the Mongo-backed `status` / `watch` commands
148
148
 
149
+ ## LLM Columns
150
+
151
+ For `llm_enrichment` in `agent` mode, the recommended path is:
152
+ - provide `config.instructions`
153
+ - let the API compile the runnable prompt
154
+ - keep `config.useAutoSchema = true`
155
+
156
+ Only send `user_schema` / `response_schema` when you intentionally want to override the generated schema and keep it aligned yourself. The installed recipe surface at `autotouch columns recipe --type llm_enrichment` follows this contract.
157
+
149
158
  ## Docs
150
159
 
151
- - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/autotouch-cli.md
152
- - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/guides/autotouch-cli-agent-playbook.md
153
- - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/research-table/reference/tables-api.md
154
- - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.46/docs/platform/authentication.md
160
+ - Full CLI reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/autotouch-cli.md
161
+ - Agent playbook: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/guides/autotouch-cli-agent-playbook.md
162
+ - Tables/API reference: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/research-table/reference/tables-api.md
163
+ - Authentication/scopes: https://github.com/nicolonic/autotouch_main/blob/autotouch-cli-v0.2.48/docs/platform/authentication.md
@@ -30,6 +30,7 @@ class ResearchTableProviderContract:
30
30
  key: str
31
31
  display_name: str
32
32
  kind: str
33
+ behavior_class: str = "standard_enrichment"
33
34
  provider_aliases: Tuple[str, ...] = ()
34
35
  origin_aliases: Tuple[str, ...] = ()
35
36
  recipe_type: Optional[str] = None
@@ -39,6 +40,7 @@ class ResearchTableProviderContract:
39
40
  setup_contract: Dict[str, Any] = field(default_factory=dict)
40
41
  execution_policy: Optional[AutoRunExecutionPolicy] = None
41
42
  dispatch_strategy: str = "bulk_queue"
43
+ readiness_strategy: Optional[str] = None
42
44
  save_time_entrypoint: Optional[str] = None
43
45
  is_action_provider: bool = False
44
46
  composition_contract: Dict[str, Any] = field(default_factory=dict)
@@ -72,10 +74,12 @@ class ResearchTableProviderContract:
72
74
  payload: Dict[str, Any] = {
73
75
  "display_name": self.display_name,
74
76
  "kind": self.kind,
77
+ "behavior_class": self.behavior_class,
75
78
  "recipe_type": self.recipe_type,
76
79
  "provider_aliases": list(self.provider_aliases or ()),
77
80
  "origin_aliases": list(self.origin_aliases or ()),
78
81
  "dispatch_strategy": self.dispatch_strategy,
82
+ "readiness_strategy": self.readiness_strategy,
79
83
  "action_provider": bool(self.is_action_provider),
80
84
  "setup_contract": deepcopy(self.setup_contract),
81
85
  "composition_contract": deepcopy(self.composition_contract),
@@ -271,6 +275,7 @@ _ADD_TO_SEQUENCE_POLICY = AutoRunExecutionPolicy(
271
275
  force_rerun=False,
272
276
  respect_existing_done=True,
273
277
  default_batch_size=50,
278
+ batch_size_env="ADD_TO_SEQUENCE_BATCH_SIZE",
274
279
  )
275
280
 
276
281
  _HTTP_REQUEST_POLICY = AutoRunExecutionPolicy(
@@ -293,6 +298,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
293
298
  key="formatter",
294
299
  display_name="Formatter",
295
300
  kind="formatter",
301
+ behavior_class="formatter",
296
302
  recipe_type="formatter",
297
303
  recipe_payload={
298
304
  "key": "engagement_statement",
@@ -343,6 +349,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
343
349
  key="llm",
344
350
  display_name="LLM Enrichment",
345
351
  kind="enrichment",
352
+ behavior_class="standard_enrichment",
346
353
  provider_aliases=_llm_provider_values(),
347
354
  recipe_type="llm_enrichment",
348
355
  recipe_payload={
@@ -365,8 +372,10 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
365
372
  },
366
373
  recipe_notes=(
367
374
  "Recommended default for agent mode: provide instructions and let the API compile the runnable prompt.",
375
+ "When the platform generates the runnable prompt from instructions, keep useAutoSchema=true unless you intentionally want to own the schema yourself.",
376
+ "Do not send user_schema/response_schema in that default generated-prompt path; prompt/schema drift is possible if you later change the generated prompt but keep a frozen custom schema.",
368
377
  "Basic is for extraction, scoring, or classification using fields already in the row. Agent is for tasks that may need outside lookup or web research.",
369
- "Create/update always materializes the runnable prompt into config.prompt/advancedPrompt before execution.",
378
+ "Create/update always materializes the runnable prompt into config.advancedPrompt before execution.",
370
379
  "Generated agent-mode prompts always include company/requester context.",
371
380
  "Basic mode stays manual-prompt-first; write the prompt directly from the user goal/preferences.",
372
381
  "Runtime only injects values for placeholders the prompt explicitly references.",
@@ -431,10 +440,10 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
431
440
  "generated": {
432
441
  "instructions_field": "config.instructions",
433
442
  "prompt_source": "generated",
434
- "materialized_prompt_fields": ["config.prompt", "config.advancedPrompt"],
443
+ "materialized_prompt_fields": ["config.advancedPrompt"],
435
444
  },
436
445
  "manual": {
437
- "prompt_field": "config.prompt",
446
+ "prompt_field": "config.advancedPrompt",
438
447
  "prompt_source": "manual",
439
448
  },
440
449
  },
@@ -477,13 +486,14 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
477
486
  ],
478
487
  },
479
488
  execution_policy=_LLM_POLICY,
480
- dispatch_strategy="llm_scheduler",
489
+ dispatch_strategy="bulk_queue",
481
490
  save_time_entrypoint="provider_save_hook",
482
491
  ),
483
492
  ResearchTableProviderContract(
484
493
  key="email_finder",
485
494
  display_name="Email Finder",
486
495
  kind="enrichment",
496
+ behavior_class="standard_enrichment",
487
497
  provider_aliases=("smart_email_finder", "email_validator", "email_finder"),
488
498
  origin_aliases=("email_finder",),
489
499
  recipe_type="email_finder",
@@ -552,6 +562,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
552
562
  key="phone_finder",
553
563
  display_name="Phone Finder",
554
564
  kind="enrichment",
565
+ behavior_class="standard_enrichment",
555
566
  provider_aliases=("smart_phone_finder", "phone_validator", "phone_finder"),
556
567
  origin_aliases=("phone_finder",),
557
568
  recipe_type="phone_finder",
@@ -626,6 +637,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
626
637
  key="lead_finder",
627
638
  display_name="Lead Finder",
628
639
  kind="enrichment",
640
+ behavior_class="standard_enrichment",
629
641
  provider_aliases=("lead_finder",),
630
642
  recipe_type="lead_finder",
631
643
  recipe_payload={
@@ -706,6 +718,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
706
718
  key="add_to_crm",
707
719
  display_name="Add to Leads",
708
720
  kind="enrichment",
721
+ behavior_class="action_enrichment",
709
722
  provider_aliases=("add_to_crm",),
710
723
  recipe_type="add_to_crm",
711
724
  recipe_payload={
@@ -794,12 +807,14 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
794
807
  ],
795
808
  },
796
809
  execution_policy=_ADD_TO_CRM_POLICY,
810
+ readiness_strategy="add_to_crm",
797
811
  is_action_provider=True,
798
812
  ),
799
813
  ResearchTableProviderContract(
800
814
  key="sync_to_table",
801
815
  display_name="Sync to Table",
802
816
  kind="enrichment",
817
+ behavior_class="action_enrichment",
803
818
  provider_aliases=("sync_to_table",),
804
819
  recipe_type="sync_to_table",
805
820
  recipe_payload={
@@ -904,12 +919,14 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
904
919
  },
905
920
  execution_policy=_SYNC_TO_TABLE_POLICY,
906
921
  dispatch_strategy="sync_to_table_prefilter",
922
+ readiness_strategy="sync_to_table",
907
923
  is_action_provider=True,
908
924
  ),
909
925
  ResearchTableProviderContract(
910
926
  key="add_to_sequence",
911
927
  display_name="Add to Sequence",
912
928
  kind="enrichment",
929
+ behavior_class="action_enrichment",
913
930
  provider_aliases=("add_to_sequence",),
914
931
  recipe_type="add_to_sequence",
915
932
  recipe_payload={
@@ -972,12 +989,14 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
972
989
  ],
973
990
  },
974
991
  execution_policy=_ADD_TO_SEQUENCE_POLICY,
992
+ readiness_strategy="add_to_sequence",
975
993
  is_action_provider=True,
976
994
  ),
977
995
  ResearchTableProviderContract(
978
996
  key="http_request",
979
997
  display_name="HTTP Request",
980
998
  kind="enrichment",
999
+ behavior_class="standard_enrichment",
981
1000
  provider_aliases=("http_request",),
982
1001
  recipe_type="http_request",
983
1002
  recipe_payload={
@@ -998,7 +1017,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
998
1017
  },
999
1018
  recipe_notes=(
1000
1019
  "Use {{column_key}} placeholders in config.url, config.headers, and config.body to reference row values.",
1001
- "Use {{secrets.name}} to resolve a workspace secret or active org integration credential by provider slug.",
1020
+ "Use {{secrets.name}} to resolve a workspace secret by name.",
1002
1021
  "body can be null, a string template, or an object whose values are templated and sent as JSON.",
1003
1022
  "The stored cell value is the parsed response body (JSON or text), not the full transport envelope.",
1004
1023
  "Preview the resolved request with `autotouch columns test-http-request --table-id <TABLE_ID> --data-file column.json` before creating or running the column.",
@@ -1038,7 +1057,7 @@ _PROVIDER_CONTRACTS: Tuple[ResearchTableProviderContract, ...] = (
1038
1057
  composition_contract={
1039
1058
  "consumes": {
1040
1059
  "kind": "row_data",
1041
- "shape": "{{column_key}} templates resolved from row cell values plus optional {{secrets.name}} org credentials",
1060
+ "shape": "{{column_key}} templates resolved from row cell values plus optional {{secrets.name}} workspace secrets",
1042
1061
  },
1043
1062
  "produces": {
1044
1063
  "kind": "json",
@@ -1308,7 +1327,7 @@ def validate_column_provider_contract(
1308
1327
  raise ProviderContractValidationError(
1309
1328
  "invalid_field",
1310
1329
  "http_request config.headers must be an object when provided.",
1311
- hint="Set config.headers to a JSON object such as {\"Authorization\": \"Bearer {{secrets.provider}}\"}.",
1330
+ hint="Set config.headers to a JSON object such as {\"Authorization\": \"Bearer {{secrets.openai_api_key}}\"}.",
1312
1331
  )
1313
1332
  body = cfg.get("body")
1314
1333
  if body is not None and not isinstance(body, (str, dict)):
@@ -1355,3 +1374,74 @@ def automation_workflow_blueprints() -> Dict[str, Dict[str, Any]]:
1355
1374
 
1356
1375
  def action_provider_keys() -> Tuple[str, ...]:
1357
1376
  return tuple(contract.key for contract in _PROVIDER_CONTRACTS if contract.is_action_provider)
1377
+
1378
+
1379
+ def behavior_class_keys(behavior_class: str) -> Tuple[str, ...]:
1380
+ normalized = _normalize(behavior_class)
1381
+ return tuple(
1382
+ contract.key
1383
+ for contract in _PROVIDER_CONTRACTS
1384
+ if _normalize(contract.behavior_class) == normalized
1385
+ )
1386
+
1387
+
1388
+ def orchestrated_runtime_provider_keys(*, include_formatter: bool = False) -> Tuple[str, ...]:
1389
+ providers: List[str] = []
1390
+ for contract in _PROVIDER_CONTRACTS:
1391
+ policy = contract.execution_policy
1392
+ if not policy:
1393
+ continue
1394
+ normalized_behavior = _normalize(contract.behavior_class)
1395
+ if normalized_behavior == "formatter":
1396
+ if include_formatter:
1397
+ providers.append(policy.orchestrator_provider)
1398
+ continue
1399
+ if contract.key == "llm":
1400
+ providers.extend(["gemini", "xai"])
1401
+ continue
1402
+ providers.append(policy.orchestrator_provider)
1403
+ return tuple(dict.fromkeys(provider for provider in providers if provider))
1404
+
1405
+
1406
+ def resolve_provider_behavior_class(
1407
+ column: Dict[str, Any],
1408
+ config: Optional[Dict[str, Any]],
1409
+ ) -> Optional[str]:
1410
+ contract = resolve_effective_provider_contract(column, config)
1411
+ if not contract:
1412
+ return None
1413
+ return contract.behavior_class
1414
+
1415
+
1416
+ def should_resolve_managed_llm_model(
1417
+ column: Dict[str, Any],
1418
+ config: Optional[Dict[str, Any]],
1419
+ ) -> bool:
1420
+ contract = resolve_effective_provider_contract(column, config)
1421
+ if not contract:
1422
+ return False
1423
+ return contract.key == "llm" and _normalize(column.get("origin")) == "ai"
1424
+
1425
+
1426
+ def resolve_runtime_orchestrator_provider(
1427
+ column: Dict[str, Any],
1428
+ config: Optional[Dict[str, Any]],
1429
+ ) -> Optional[str]:
1430
+ contract = resolve_effective_provider_contract(column, config)
1431
+ if not contract or not contract.execution_policy:
1432
+ return None
1433
+ if _normalize(contract.behavior_class) == "formatter":
1434
+ return None
1435
+ if contract.key == "llm":
1436
+ runtime_provider = _normalize((config or {}).get("provider"))
1437
+ if runtime_provider in {"gemini", "xai"}:
1438
+ return runtime_provider
1439
+ return None
1440
+ return contract.execution_policy.orchestrator_provider
1441
+
1442
+
1443
+ def uses_orchestrated_bulk_run(
1444
+ column: Dict[str, Any],
1445
+ config: Optional[Dict[str, Any]],
1446
+ ) -> bool:
1447
+ return resolve_runtime_orchestrator_provider(column, config) is not None
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "autotouch-cli"
7
- version = "0.2.46"
7
+ version = "0.2.48"
8
8
  description = "Autotouch Smart Table CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes