agentle 0.9.40__py3-none-any.whl → 0.9.42__py3-none-any.whl
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.
- agentle/agents/whatsapp/models/whatsapp_message.py +1 -1
- agentle/agents/whatsapp/models/whatsapp_webhook_payload.py +49 -8
- agentle/agents/whatsapp/providers/evolution/evolution_api_provider.py +21 -68
- agentle/agents/whatsapp/whatsapp_bot.py +11 -11
- {agentle-0.9.40.dist-info → agentle-0.9.42.dist-info}/METADATA +1 -1
- {agentle-0.9.40.dist-info → agentle-0.9.42.dist-info}/RECORD +8 -8
- {agentle-0.9.40.dist-info → agentle-0.9.42.dist-info}/WHEEL +0 -0
- {agentle-0.9.40.dist-info → agentle-0.9.42.dist-info}/licenses/LICENSE +0 -0
|
@@ -24,7 +24,7 @@ class WhatsAppMessage(BaseModel):
|
|
|
24
24
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
25
25
|
remote_jid: str | None = Field(
|
|
26
26
|
default=None,
|
|
27
|
-
description="Actual WhatsApp JID for sending messages
|
|
27
|
+
description="Actual WhatsApp JID for sending messages back to the contact",
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
@override
|
|
@@ -77,18 +77,59 @@ class WhatsAppWebhookPayload(BaseModel):
|
|
|
77
77
|
ForwardedFrom: str | None = Field(default=None) # For forwarded messages
|
|
78
78
|
FrequentlyForwarded: str | None = Field(default=None) # "true" or "false" as string
|
|
79
79
|
|
|
80
|
+
# Root level fallbacks for robust extraction
|
|
81
|
+
remoteJid: str | None = Field(default=None)
|
|
82
|
+
remoteJidAlt: str | None = Field(default=None)
|
|
83
|
+
|
|
80
84
|
def model_post_init(self, context: Any, /) -> None:
|
|
81
|
-
if self.phone_number_id
|
|
85
|
+
if self.phone_number_id:
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
# Initialize data if missing but root fields are present
|
|
89
|
+
if not self.data and (self.remoteJid or self.remoteJidAlt):
|
|
90
|
+
from agentle.agents.whatsapp.models.key import Key
|
|
91
|
+
from agentle.agents.whatsapp.models.data import Data
|
|
92
|
+
|
|
93
|
+
self.data = Data(
|
|
94
|
+
key=Key(
|
|
95
|
+
remoteJid=self.remoteJid or self.remoteJidAlt or "", fromMe=False
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if not self.data:
|
|
82
100
|
return
|
|
83
101
|
|
|
84
102
|
key = self.data.key
|
|
85
|
-
if "@lid" in key.remoteJid:
|
|
86
|
-
remote_jid_alt = key.remoteJidAlt
|
|
87
|
-
if remote_jid_alt is None:
|
|
88
|
-
raise ValueError("No remotejidalt was provided.")
|
|
89
103
|
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
# Extraction logic:
|
|
105
|
+
# 1. key.remoteJid
|
|
106
|
+
# 2. remoteJid (root)
|
|
107
|
+
# 3. key.remoteJidAlt
|
|
108
|
+
# 4. remoteJidAlt (root)
|
|
109
|
+
|
|
110
|
+
candidates = [
|
|
111
|
+
key.remoteJid,
|
|
112
|
+
self.remoteJid,
|
|
113
|
+
key.remoteJidAlt,
|
|
114
|
+
self.remoteJidAlt,
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
# Find first valid candidate
|
|
118
|
+
selected_jid = next((c for c in candidates if c), None)
|
|
119
|
+
|
|
120
|
+
if not selected_jid:
|
|
92
121
|
return
|
|
93
122
|
|
|
94
|
-
|
|
123
|
+
# Handle @lid: Evolution API sometimes sends @lid in remoteJid,
|
|
124
|
+
# but provides the correct @s.whatsapp.net format in remoteJidAlt.
|
|
125
|
+
# In this case, prefer remoteJidAlt.
|
|
126
|
+
if "@lid" in selected_jid:
|
|
127
|
+
alt_candidates = [key.remoteJidAlt, self.remoteJidAlt]
|
|
128
|
+
alt_jid = next((c for c in alt_candidates if c), None)
|
|
129
|
+
if alt_jid:
|
|
130
|
+
selected_jid = alt_jid
|
|
131
|
+
|
|
132
|
+
self.phone_number_id = selected_jid.split("@")[0]
|
|
133
|
+
|
|
134
|
+
# Store the selected JID in data.key for downstream use
|
|
135
|
+
self.data.key.remoteJid = selected_jid
|
|
@@ -752,8 +752,7 @@ class EvolutionAPIProvider(WhatsAppProvider):
|
|
|
752
752
|
logger.debug(f"Message is quoting message ID: {quoted_message_id}")
|
|
753
753
|
|
|
754
754
|
try:
|
|
755
|
-
#
|
|
756
|
-
# This is essential for @lid numbers (Brazilian WhatsApp contacts)
|
|
755
|
+
# Check if there's a stored remoteJid for this contact
|
|
757
756
|
session = await self.get_session(to)
|
|
758
757
|
remote_jid = session.context_data.get("remote_jid") if session else None
|
|
759
758
|
|
|
@@ -1117,8 +1116,7 @@ class EvolutionAPIProvider(WhatsAppProvider):
|
|
|
1117
1116
|
logger.debug(f"Sending typing indicator to {to} for {duration}s")
|
|
1118
1117
|
|
|
1119
1118
|
try:
|
|
1120
|
-
#
|
|
1121
|
-
# This is essential for @lid numbers (Brazilian WhatsApp contacts)
|
|
1119
|
+
# Check if there's a stored remoteJid for this contact
|
|
1122
1120
|
session = await self.get_session(to)
|
|
1123
1121
|
remote_jid = session.context_data.get("remote_jid") if session else None
|
|
1124
1122
|
|
|
@@ -1179,8 +1177,7 @@ class EvolutionAPIProvider(WhatsAppProvider):
|
|
|
1179
1177
|
logger.debug(f"Sending recording indicator to {to} for {duration}s")
|
|
1180
1178
|
|
|
1181
1179
|
try:
|
|
1182
|
-
#
|
|
1183
|
-
# This is essential for @lid numbers (Brazilian WhatsApp contacts)
|
|
1180
|
+
# Check if there's a stored remoteJid for this contact
|
|
1184
1181
|
session = await self.get_session(to)
|
|
1185
1182
|
remote_jid = session.context_data.get("remote_jid") if session else None
|
|
1186
1183
|
|
|
@@ -1597,78 +1594,34 @@ class EvolutionAPIProvider(WhatsAppProvider):
|
|
|
1597
1594
|
Normalize phone number to Evolution API format.
|
|
1598
1595
|
|
|
1599
1596
|
Evolution API expects phone numbers in the format: countrycode+number@s.whatsapp.net
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1597
|
+
|
|
1598
|
+
This function:
|
|
1599
|
+
- Removes any existing suffix (@s.whatsapp.net, @lid, etc.)
|
|
1600
|
+
- Strips non-numeric characters
|
|
1601
|
+
- Adds country code 55 if not present
|
|
1602
|
+
- Appends @s.whatsapp.net suffix
|
|
1603
|
+
|
|
1604
|
+
NOTE: This function does NOT modify the number itself (no '9' insertion).
|
|
1605
|
+
The number is sent exactly as provided by the user/webhook.
|
|
1604
1606
|
"""
|
|
1605
1607
|
original_phone = phone
|
|
1606
1608
|
|
|
1607
|
-
# Remove
|
|
1608
|
-
if "@
|
|
1609
|
-
phone = phone.split("@")[0]
|
|
1610
|
-
elif "@lid" in phone:
|
|
1609
|
+
# Remove any @ suffix if present
|
|
1610
|
+
if "@" in phone:
|
|
1611
1611
|
phone = phone.split("@")[0]
|
|
1612
1612
|
|
|
1613
1613
|
# Remove non-numeric characters
|
|
1614
1614
|
phone = "".join(c for c in phone if c.isdigit())
|
|
1615
1615
|
|
|
1616
|
-
#
|
|
1616
|
+
# Add country code 55 if not present
|
|
1617
1617
|
if not phone.startswith("55"):
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
phone = "55" + phone
|
|
1623
|
-
logger.debug(
|
|
1624
|
-
f"Added country code 55 to phone: {original_phone} -> {phone}"
|
|
1625
|
-
)
|
|
1626
|
-
elif len(phone) == 10:
|
|
1627
|
-
# Old format without the 9: DDD (2) + 8 digits = 10 digits
|
|
1628
|
-
# Example: 3498137839 -> 5534998137839
|
|
1629
|
-
# Insert '9' after area code (first 2 digits)
|
|
1630
|
-
phone = "55" + phone[:2] + "9" + phone[2:]
|
|
1631
|
-
logger.warning(
|
|
1632
|
-
f"Converted old format phone number: {original_phone} -> {phone}"
|
|
1633
|
-
)
|
|
1634
|
-
else:
|
|
1635
|
-
# Unknown format, but add 55 anyway
|
|
1636
|
-
phone = "55" + phone
|
|
1637
|
-
logger.warning(
|
|
1638
|
-
f"Unknown phone format, added 55: {original_phone} -> {phone}"
|
|
1639
|
-
)
|
|
1640
|
-
|
|
1641
|
-
# Validate Brazilian mobile format
|
|
1642
|
-
if phone.startswith("55"):
|
|
1643
|
-
# Should have 13 digits total: 55 + DDD (2) + 9 + 8 digits
|
|
1644
|
-
if len(phone) == 12:
|
|
1645
|
-
# Missing the '9' after area code
|
|
1646
|
-
# Example: 553498137839 -> 5534998137839
|
|
1647
|
-
# Insert '9' after 55 + DDD (after position 4)
|
|
1648
|
-
phone = phone[:4] + "9" + phone[4:]
|
|
1649
|
-
logger.warning(
|
|
1650
|
-
f"Fixed missing '9' in phone number: {original_phone} -> {phone}"
|
|
1651
|
-
)
|
|
1652
|
-
elif len(phone) != 13:
|
|
1653
|
-
logger.error(
|
|
1654
|
-
f"Invalid Brazilian mobile number length: {phone} (expected 13 digits, got {len(phone)})"
|
|
1655
|
-
)
|
|
1656
|
-
|
|
1657
|
-
# Validate that the 5th digit is '9' (mobile indicator)
|
|
1658
|
-
if len(phone) >= 5 and phone[4] != "9":
|
|
1659
|
-
logger.warning(
|
|
1660
|
-
f"Phone number may be invalid - 5th digit is not '9': {phone}"
|
|
1661
|
-
)
|
|
1618
|
+
phone = "55" + phone
|
|
1619
|
+
logger.debug(
|
|
1620
|
+
f"Added country code 55 to phone: {original_phone} -> {phone}"
|
|
1621
|
+
)
|
|
1662
1622
|
|
|
1663
|
-
#
|
|
1664
|
-
|
|
1665
|
-
if phone.startswith("55"):
|
|
1666
|
-
# Brazilian number - use @lid
|
|
1667
|
-
phone = phone + "@lid"
|
|
1668
|
-
logger.info(f"🧪 TESTING: Using @lid for Brazilian number: {phone}")
|
|
1669
|
-
else:
|
|
1670
|
-
# Non-Brazilian number - use @s.whatsapp.net
|
|
1671
|
-
phone = phone + "@s.whatsapp.net"
|
|
1623
|
+
# Always use @s.whatsapp.net for normal numbers
|
|
1624
|
+
phone = phone + "@s.whatsapp.net"
|
|
1672
1625
|
|
|
1673
1626
|
if original_phone != phone:
|
|
1674
1627
|
logger.info(f"Phone number normalized: {original_phone} -> {phone}")
|
|
@@ -415,7 +415,7 @@ class WhatsAppBot[T_Schema: WhatsAppResponseBase = WhatsAppResponseBase](BaseMod
|
|
|
415
415
|
f"[MESSAGE_HANDLER] Stored custom chat_id in session: {chat_id}"
|
|
416
416
|
)
|
|
417
417
|
|
|
418
|
-
#
|
|
418
|
+
# Store remoteJid for later use when sending messages
|
|
419
419
|
if message.remote_jid:
|
|
420
420
|
session.context_data["remote_jid"] = message.remote_jid
|
|
421
421
|
logger.info(
|
|
@@ -3478,12 +3478,17 @@ class WhatsAppBot[T_Schema: WhatsAppResponseBase = WhatsAppResponseBase](BaseMod
|
|
|
3478
3478
|
|
|
3479
3479
|
logger.info("[MESSAGE_UPSERT] Parsing message from Evolution API data")
|
|
3480
3480
|
# Parse message directly from data (which contains the message info)
|
|
3481
|
+
# When remoteJid contains @lid, use remoteJidAlt which has the correct @s.whatsapp.net format
|
|
3482
|
+
from_number = payload.data.key.remoteJid
|
|
3483
|
+
if "@lid" in payload.data.key.remoteJid and payload.data.key.remoteJidAlt:
|
|
3484
|
+
from_number = payload.data.key.remoteJidAlt
|
|
3485
|
+
logger.info(
|
|
3486
|
+
f"[MESSAGE_UPSERT] 🔄 Using remoteJidAlt instead of @lid: {from_number}"
|
|
3487
|
+
)
|
|
3481
3488
|
|
|
3482
3489
|
message = self._parse_evolution_message_from_data(
|
|
3483
3490
|
data,
|
|
3484
|
-
from_number=
|
|
3485
|
-
if "@lid" in payload.data.key.remoteJid
|
|
3486
|
-
else payload.data.key.remoteJid,
|
|
3491
|
+
from_number=from_number,
|
|
3487
3492
|
)
|
|
3488
3493
|
|
|
3489
3494
|
if message:
|
|
@@ -3491,13 +3496,8 @@ class WhatsAppBot[T_Schema: WhatsAppResponseBase = WhatsAppResponseBase](BaseMod
|
|
|
3491
3496
|
f"[MESSAGE_UPSERT] ✅ Parsed message: {message.id} from {message.from_number}"
|
|
3492
3497
|
)
|
|
3493
3498
|
|
|
3494
|
-
#
|
|
3495
|
-
|
|
3496
|
-
if "@lid" in payload.data.key.remoteJid:
|
|
3497
|
-
logger.info(
|
|
3498
|
-
f"[MESSAGE_UPSERT] 🔑 Detected @lid number. Storing remoteJid: {payload.data.key.remoteJid} for phone: {message.from_number}"
|
|
3499
|
-
)
|
|
3500
|
-
message.remote_jid = payload.data.key.remoteJid
|
|
3499
|
+
# Store the remoteJid for later use when sending messages back
|
|
3500
|
+
message.remote_jid = from_number
|
|
3501
3501
|
|
|
3502
3502
|
logger.info(
|
|
3503
3503
|
f"[MESSAGE_UPSERT] About to call handle_message with {len(self._response_callbacks)} callbacks"
|
|
@@ -137,7 +137,7 @@ agentle/agents/ui/__init__.py,sha256=IjHRV0k2DNwvFrEHebmsXiBvmITE8nQUnsR07h9tVkU
|
|
|
137
137
|
agentle/agents/ui/streamlit.py,sha256=9afICL0cxtG1o2pWh6vH39-NdKiVfADKiXo405F2aB0,42829
|
|
138
138
|
agentle/agents/whatsapp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
139
139
|
agentle/agents/whatsapp/human_delay_calculator.py,sha256=BGCDeoNTPsMn4d_QYmG0BWGCG8SiUJC6Fk295ulAsAk,18268
|
|
140
|
-
agentle/agents/whatsapp/whatsapp_bot.py,sha256=
|
|
140
|
+
agentle/agents/whatsapp/whatsapp_bot.py,sha256=n3GPOI3HfahTrJyDcaNYXNSm8yKJX1xAeUXx0wG0HTw,169926
|
|
141
141
|
agentle/agents/whatsapp/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
142
142
|
agentle/agents/whatsapp/models/audio_message.py,sha256=af2apMWzxKcCtXfQN6U2qfOFoiwRj0nCUrKmrBD0whE,3067
|
|
143
143
|
agentle/agents/whatsapp/models/context_info.py,sha256=sk80KuNE36S6VRnLh7n6UXmzZCXIB4E4lNxnRyVizg8,563
|
|
@@ -158,20 +158,20 @@ agentle/agents/whatsapp/models/whatsapp_document_message.py,sha256=ECM_hXF-3IbC9
|
|
|
158
158
|
agentle/agents/whatsapp/models/whatsapp_image_message.py,sha256=xOAPRRSgqj9gQ2ZZOGdFWfOgtmNpE1W8mIUAmB5YTpo,314
|
|
159
159
|
agentle/agents/whatsapp/models/whatsapp_location_message.py,sha256=CJCJR1DHjrN92OloNopvUteUxUxeEpHlWQSJhj6Ive4,407
|
|
160
160
|
agentle/agents/whatsapp/models/whatsapp_media_message.py,sha256=xmYE0SVdL7UIJuYRWJTfCoGAd5-pyXBnueaxFaECuXg,386
|
|
161
|
-
agentle/agents/whatsapp/models/whatsapp_message.py,sha256=
|
|
161
|
+
agentle/agents/whatsapp/models/whatsapp_message.py,sha256=u0HrWuK--cRNX96avYbiWkInHYYH67TOXI9XSNOS_BI,1209
|
|
162
162
|
agentle/agents/whatsapp/models/whatsapp_message_status.py,sha256=jDWShdvSve5EhkgtDkh1jZmpRVNoXCokv4M6at1eSIU,214
|
|
163
163
|
agentle/agents/whatsapp/models/whatsapp_message_type.py,sha256=GctIGOC1Bc_D_L0ehEmEwgxePFx0ioTEUoBlZEdxdG8,279
|
|
164
164
|
agentle/agents/whatsapp/models/whatsapp_response_base.py,sha256=IIDONx9Ipt593tAZvoc8dPDUISeNH-WOpRP1x_-Q6Gk,1145
|
|
165
165
|
agentle/agents/whatsapp/models/whatsapp_session.py,sha256=9G1HC-A2G9jTdpwYy3w9bnYkOGK2vvA7kdYAf32oWMU,15640
|
|
166
166
|
agentle/agents/whatsapp/models/whatsapp_text_message.py,sha256=GpSwFrPC4qpQlVCWKKgYjQJKNv0qvwgYfuoD3ttLzdQ,441
|
|
167
167
|
agentle/agents/whatsapp/models/whatsapp_video_message.py,sha256=-d-4hnkkxyLVNoje3a1pOEAvzWqoCLFcBn70wUpnyXY,346
|
|
168
|
-
agentle/agents/whatsapp/models/whatsapp_webhook_payload.py,sha256=
|
|
168
|
+
agentle/agents/whatsapp/models/whatsapp_webhook_payload.py,sha256=N3ERXDcQKC6Vd5k2nlhlpP1EeYN5v5OsDkIUdeFv9U4,5562
|
|
169
169
|
agentle/agents/whatsapp/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
170
170
|
agentle/agents/whatsapp/providers/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
171
171
|
agentle/agents/whatsapp/providers/base/whatsapp_provider.py,sha256=Iaywrv0xer4fhZprMttC-NP4-rRYdU_45UzIZQ7dkYA,5349
|
|
172
172
|
agentle/agents/whatsapp/providers/evolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
173
173
|
agentle/agents/whatsapp/providers/evolution/evolution_api_config.py,sha256=mc3jVJ1olnFgt7jP6P_eygvUVhN3XYSAYp1ozIxtAsc,1288
|
|
174
|
-
agentle/agents/whatsapp/providers/evolution/evolution_api_provider.py,sha256=
|
|
174
|
+
agentle/agents/whatsapp/providers/evolution/evolution_api_provider.py,sha256=QufRuXBtreBGEfSpfJz1wnQCGjifAu_N9AZUmjyFeyY,66584
|
|
175
175
|
agentle/agents/whatsapp/providers/meta/__init__.py,sha256=ArZ2y9qUALahP2-c0j0ESFKmRjDHiZIurqxYC7MTWA8,1038
|
|
176
176
|
agentle/agents/whatsapp/providers/meta/meta_whatsapp_config.py,sha256=ECzb76Sba0ExrO4NAB7v9HLlgAxsjyTg57mewdVt8EY,1257
|
|
177
177
|
agentle/agents/whatsapp/providers/meta/meta_whatsapp_provider.py,sha256=95xvVrqp6f5Ku49fqOEHUhJUIJPGb1rRvCntoIY2JSM,35953
|
|
@@ -1018,7 +1018,7 @@ agentle/web/actions/scroll.py,sha256=WqVVAORNDK3BL1oASZBPmXJYeSVkPgAOmWA8ibYO82I
|
|
|
1018
1018
|
agentle/web/actions/viewport.py,sha256=KCwm88Pri19Qc6GLHC69HsRxmdJz1gEEAODfggC_fHo,287
|
|
1019
1019
|
agentle/web/actions/wait.py,sha256=IKEywjf-KC4ni9Gkkv4wgc7bY-hk7HwD4F-OFWlyf2w,571
|
|
1020
1020
|
agentle/web/actions/write_text.py,sha256=9mxfHcpKs_L7BsDnJvOYHQwG8M0GWe61SRJAsKk3xQ8,748
|
|
1021
|
-
agentle-0.9.
|
|
1022
|
-
agentle-0.9.
|
|
1023
|
-
agentle-0.9.
|
|
1024
|
-
agentle-0.9.
|
|
1021
|
+
agentle-0.9.42.dist-info/METADATA,sha256=d2ra_dRi9kbEYhixrDlJGsCRuC63r9iviZfgpOOsEk4,86879
|
|
1022
|
+
agentle-0.9.42.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
1023
|
+
agentle-0.9.42.dist-info/licenses/LICENSE,sha256=T90S9vqRS6qP-voULxAcvwEs558wRRo6dHuZrjgcOUI,1085
|
|
1024
|
+
agentle-0.9.42.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|