adloop 0.22.1__tar.gz → 0.22.2__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 (66) hide show
  1. {adloop-0.22.1 → adloop-0.22.2}/PKG-INFO +1 -1
  2. {adloop-0.22.1 → adloop-0.22.2}/pyproject.toml +1 -1
  3. {adloop-0.22.1 → adloop-0.22.2}/pyproject.toml.orig +1 -1
  4. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gsc/reports.py +6 -2
  5. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/merchant/read.py +5 -2
  6. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/reddit/read.py +6 -2
  7. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/runtime.py +14 -0
  8. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/server.py +11 -5
  9. {adloop-0.22.1 → adloop-0.22.2}/README.md +0 -0
  10. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/__init__.py +0 -0
  11. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/__main__.py +0 -0
  12. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/_mcp_patches.py +0 -0
  13. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/__init__.py +0 -0
  14. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/ai_max.py +0 -0
  15. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/brands.py +0 -0
  16. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/client.py +0 -0
  17. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/conversion_actions.py +0 -0
  18. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/currency.py +0 -0
  19. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/custom_conversion_goals.py +0 -0
  20. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/enums.py +0 -0
  21. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/forecast.py +0 -0
  22. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/gaql.py +0 -0
  23. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/image_fetch.py +0 -0
  24. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/pmax.py +0 -0
  25. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/read.py +0 -0
  26. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/validate_only.py +0 -0
  27. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ads/write.py +0 -0
  28. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/auth.py +0 -0
  29. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/cli.py +0 -0
  30. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/config.py +0 -0
  31. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/crossref.py +0 -0
  32. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/diagnostics.py +0 -0
  33. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ga4/__init__.py +0 -0
  34. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ga4/client.py +0 -0
  35. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ga4/reports.py +0 -0
  36. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ga4/tracking.py +0 -0
  37. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/ga4/write.py +0 -0
  38. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gsc/__init__.py +0 -0
  39. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gsc/client.py +0 -0
  40. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gtm/__init__.py +0 -0
  41. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gtm/client.py +0 -0
  42. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gtm/entities.py +0 -0
  43. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gtm/read.py +0 -0
  44. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/gtm/write.py +0 -0
  45. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/merchant/__init__.py +0 -0
  46. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/merchant/client.py +0 -0
  47. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/pagespeed.py +0 -0
  48. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/reddit/__init__.py +0 -0
  49. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/reddit/auth.py +0 -0
  50. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/reddit/client.py +0 -0
  51. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/reddit/schedule.py +0 -0
  52. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/reddit/write.py +0 -0
  53. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/__init__.py +0 -0
  54. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/adloop.md +0 -0
  55. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/commands/analyze-performance.md +0 -0
  56. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/commands/budget-plan.md +0 -0
  57. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/commands/create-ad.md +0 -0
  58. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/commands/create-campaign.md +0 -0
  59. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/commands/diagnose-tracking.md +0 -0
  60. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules/commands/optimize-campaign.md +0 -0
  61. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/rules_install.py +0 -0
  62. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/safety/__init__.py +0 -0
  63. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/safety/audit.py +0 -0
  64. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/safety/guards.py +0 -0
  65. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/safety/preview.py +0 -0
  66. {adloop-0.22.1 → adloop-0.22.2}/src/adloop/tracking.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: adloop
3
- Version: 0.22.1
3
+ Version: 0.22.2
4
4
  Summary: The AI command center for Google Ads, Reddit Ads, GA4, and tracking code.
5
5
  Keywords: mcp,google-ads,reddit-ads,google-analytics,ga4,cursor,marketing
6
6
  Author: Daniel Klose
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "adloop"
3
- version = "0.22.1"
3
+ version = "0.22.2"
4
4
  description = "The AI command center for Google Ads, Reddit Ads, GA4, and tracking code."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "adloop"
3
- version = "0.22.1"
3
+ version = "0.22.2"
4
4
  description = "The AI command center for Google Ads, Reddit Ads, GA4, and tracking code."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -101,9 +101,13 @@ def run_gsc_report(
101
101
  site_url = config.gsc.site_url
102
102
 
103
103
  if not site_url:
104
+ from adloop.runtime import default_setting_hint
105
+
104
106
  return {
105
- "error": "site_url is required. Pass it as an argument or set "
106
- "gsc.site_url in ~/.adloop/config.yaml."
107
+ "error": "site_url is required. Pass it as an argument (see "
108
+ "list_gsc_sites) or "
109
+ + default_setting_hint("gsc.site_url", "Settings → Google & accounts")
110
+ + "."
107
111
  }
108
112
 
109
113
  dimensions = [_normalize_dimension(d) for d in (dimensions or ["query"])]
@@ -126,6 +126,8 @@ def get_merchant_feed_health(
126
126
 
127
127
  account_id = str(account_id or "").strip() or config.merchant.account_id.strip()
128
128
  if not account_id:
129
+ from adloop.runtime import default_setting_hint
130
+
129
131
  return {
130
132
  "error": (
131
133
  "account_id is required: no Merchant Center account was "
@@ -133,8 +135,9 @@ def get_merchant_feed_health(
133
135
  ),
134
136
  "hint": (
135
137
  "Call list_merchant_accounts to find the numeric Merchant "
136
- "Center ID and pass it as account_id, or set "
137
- "merchant.account_id in the config to make it the default."
138
+ "Center ID and pass it as account_id, or "
139
+ + default_setting_hint("merchant.account_id", "Settings → Google & accounts")
140
+ + "."
138
141
  ),
139
142
  }
140
143
  if not account_id.isdigit():
@@ -103,9 +103,13 @@ def resolve_account(config: AdLoopConfig, ad_account_id: str = "") -> str:
103
103
  """Explicit id wins, then ``reddit.ad_account_id`` from the config."""
104
104
  account = (ad_account_id or config.reddit.ad_account_id or "").strip()
105
105
  if not account:
106
+ from adloop.runtime import default_setting_hint
107
+
106
108
  raise ValueError(
107
- "ad_account_id is required — pass it explicitly (see "
108
- "list_reddit_accounts) or set reddit.ad_account_id in the config."
109
+ "ad_account_id is required: pass it explicitly (see "
110
+ "list_reddit_accounts) or "
111
+ + default_setting_hint("reddit.ad_account_id", "Settings → Reddit Ads")
112
+ + "."
109
113
  )
110
114
  return account
111
115
 
@@ -64,6 +64,20 @@ def tool_visibility() -> ToolVisibility | None:
64
64
  return _tool_visibility
65
65
 
66
66
 
67
+ def default_setting_hint(config_key: str, dashboard_page: str) -> str:
68
+ """How to set a missing default, phrased for where AdLoop runs.
69
+
70
+ Self-hosted it is a key in the config file; a hosted runtime has no
71
+ config file the user can edit, so it names the dashboard page instead.
72
+ """
73
+ if _deployment_mode == "server":
74
+ return (
75
+ f"choose a default under {dashboard_page} in the AdLoop Cloud "
76
+ "dashboard (agencies: per client under Settings → Clients)"
77
+ )
78
+ return f"set {config_key} in the config (~/.adloop/config.yaml)"
79
+
80
+
67
81
  def deployment_mode() -> DeploymentMode:
68
82
  """Return the process-wide deployment mode ("local" or "server")."""
69
83
  return _deployment_mode
@@ -155,10 +155,13 @@ def _gtm_defaults(account_id: str, container_id: str) -> tuple[str, str]:
155
155
  account_id = account_id or cfg.account_id
156
156
  container_id = container_id or cfg.container_id
157
157
  if not account_id or not container_id:
158
+ from adloop.runtime import default_setting_hint
159
+
158
160
  raise ValueError(
159
- "gtm_account_id and gtm_container_id are required — pass them "
160
- "explicitly (see list_gtm_accounts / list_gtm_containers) or set "
161
- "gtm.account_id / gtm.container_id in the config."
161
+ "gtm_account_id and gtm_container_id are required: pass them "
162
+ "explicitly (see list_gtm_accounts / list_gtm_containers) or "
163
+ + default_setting_hint("gtm.account_id / gtm.container_id", "Settings → Google & accounts")
164
+ + "."
162
165
  )
163
166
  return account_id, container_id
164
167
 
@@ -1790,9 +1793,12 @@ def list_gtm_containers(gtm_account_id: str = "") -> dict:
1790
1793
 
1791
1794
  gtm_account_id = gtm_account_id or current_config().gtm.account_id
1792
1795
  if not gtm_account_id:
1796
+ from adloop.runtime import default_setting_hint
1797
+
1793
1798
  raise ValueError(
1794
- "gtm_account_id is required — call list_gtm_accounts first or "
1795
- "set gtm.account_id in the config."
1799
+ "gtm_account_id is required: call list_gtm_accounts first or "
1800
+ + default_setting_hint("gtm.account_id", "Settings → Google & accounts")
1801
+ + "."
1796
1802
  )
1797
1803
  return _impl(current_config(), account_id=gtm_account_id)
1798
1804
 
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