agentle 0.9.26__py3-none-any.whl → 0.9.28__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.
@@ -592,9 +592,11 @@ class Endpoint(BaseModel):
592
592
 
593
593
  tool_parameters[param.name] = param_info
594
594
 
595
+ tool_name = "_".join(self.name.lower().split())
596
+
595
597
  # Create the tool
596
598
  tool = Tool(
597
- name=self.name,
599
+ name=tool_name,
598
600
  description=self.get_enhanced_description(),
599
601
  parameters=tool_parameters,
600
602
  )
@@ -1,4 +1,4 @@
1
- from rsb.models.base_model import BaseModel
1
+ from rsb.models import BaseModel, Field
2
2
 
3
3
 
4
4
  class Key(BaseModel):
@@ -11,6 +11,6 @@ class Key(BaseModel):
11
11
  """
12
12
 
13
13
  remoteJid: str
14
- remoteJidAlt: str
14
+ remoteJidAlt: str = Field(default="")
15
15
  fromMe: bool
16
16
  id: str
@@ -0,0 +1,31 @@
1
+ # Em: agentle/agents/whatsapp/models/whatsapp_response_base.py
2
+
3
+ from rsb.models.base_model import BaseModel
4
+ from rsb.models.field import Field
5
+
6
+
7
+ class WhatsAppResponseBase(BaseModel):
8
+ """
9
+ Base class for WhatsApp bot structured responses.
10
+
11
+ This class ensures that all structured outputs from the WhatsApp bot
12
+ contain a 'response' field with the text to be sent to the user.
13
+
14
+ Developers can extend this class to add additional structured data
15
+ that they want to extract from the conversation.
16
+
17
+ Example:
18
+ ```python
19
+ class CustomerServiceResponse(WhatsAppResponseBase):
20
+ response: str # Inherited - text to send to user
21
+ sentiment: Literal["happy", "neutral", "frustrated", "angry"]
22
+ urgency: int = Field(ge=1, le=5, description="Urgency level 1-5")
23
+ requires_human: bool = False
24
+ suggested_actions: list[str] = Field(default_factory=list)
25
+ ```
26
+ """
27
+
28
+ response: str = Field(
29
+ ...,
30
+ description="The text response that will be sent to the WhatsApp user. This field is required.",
31
+ )
@@ -33,6 +33,7 @@ from agentle.agents.whatsapp.models.whatsapp_document_message import (
33
33
  from agentle.agents.whatsapp.models.whatsapp_image_message import WhatsAppImageMessage
34
34
  from agentle.agents.whatsapp.models.whatsapp_media_message import WhatsAppMediaMessage
35
35
  from agentle.agents.whatsapp.models.whatsapp_message import WhatsAppMessage
36
+ from agentle.agents.whatsapp.models.whatsapp_response_base import WhatsAppResponseBase
36
37
  from agentle.agents.whatsapp.models.whatsapp_session import WhatsAppSession
37
38
  from agentle.agents.whatsapp.models.whatsapp_text_message import WhatsAppTextMessage
38
39
  from agentle.agents.whatsapp.models.whatsapp_video_message import WhatsAppVideoMessage
@@ -128,14 +129,42 @@ class CallbackWithContext:
128
129
  context: dict[str, Any] = field(default_factory=dict)
129
130
 
130
131
 
131
- class WhatsAppBot(BaseModel):
132
+ class WhatsAppBot[T_Schema: WhatsAppResponseBase = WhatsAppResponseBase](BaseModel):
132
133
  """
133
134
  WhatsApp bot that wraps an Agentle agent with enhanced message batching and spam protection.
134
135
 
135
- Now uses the Agent's conversation store directly instead of managing contexts separately.
136
+ Now supports structured outputs through generic type parameter T_Schema.
137
+ The schema must extend WhatsAppResponseBase to ensure a 'response' field is always present.
138
+
139
+ Examples:
140
+ ```python
141
+ # Basic usage (no structured output)
142
+ agent = Agent(...)
143
+ bot = WhatsAppBot(agent=agent, provider=provider)
144
+
145
+ # With structured output
146
+ class MyResponse(WhatsAppResponseBase):
147
+ sentiment: Literal["happy", "sad", "neutral"]
148
+ urgency_level: int
149
+
150
+ agent = Agent[MyResponse](
151
+ response_schema=MyResponse,
152
+ instructions="Extract sentiment and urgency from the conversation..."
153
+ )
154
+ bot = WhatsAppBot[MyResponse](agent=agent, provider=provider)
155
+
156
+ # Access structured data in callbacks
157
+ async def my_callback(phone, chat_id, response, context):
158
+ if response and response.parsed:
159
+ print(f"Sentiment: {response.parsed.sentiment}")
160
+ print(f"Urgency: {response.parsed.urgency_level}")
161
+ # response.parsed.response is automatically sent to WhatsApp
162
+
163
+ bot.add_response_callback(my_callback)
164
+ ```
136
165
  """
137
166
 
138
- agent: Agent[Any]
167
+ agent: Agent[T_Schema]
139
168
  provider: WhatsAppProvider
140
169
  tts_provider: TtsProvider | None = Field(default=None)
141
170
  file_storage_manager: FileStorageManager | None = Field(default=None)
@@ -1302,7 +1331,7 @@ class WhatsAppBot(BaseModel):
1302
1331
 
1303
1332
  async def _process_message_batch(
1304
1333
  self, phone_number: PhoneNumber, session: WhatsAppSession, processing_token: str
1305
- ) -> GeneratedAssistantMessage[Any] | None:
1334
+ ) -> GeneratedAssistantMessage[T_Schema] | None:
1306
1335
  """Process a batch of messages for a user with enhanced timeout protection.
1307
1336
 
1308
1337
  This method processes multiple messages that were received in quick succession
@@ -1504,7 +1533,7 @@ class WhatsAppBot(BaseModel):
1504
1533
  message: WhatsAppMessage,
1505
1534
  session: WhatsAppSession,
1506
1535
  chat_id: ChatId | None = None,
1507
- ) -> GeneratedAssistantMessage[Any]:
1536
+ ) -> GeneratedAssistantMessage[T_Schema]:
1508
1537
  """Process a single message immediately with quote message support."""
1509
1538
  logger.info(
1510
1539
  "[SINGLE_MESSAGE] ═══════════ SINGLE MESSAGE PROCESSING START ═══════════"
@@ -2207,7 +2236,7 @@ class WhatsAppBot(BaseModel):
2207
2236
  async def _send_response(
2208
2237
  self,
2209
2238
  to: PhoneNumber,
2210
- response: GeneratedAssistantMessage[Any] | str,
2239
+ response: GeneratedAssistantMessage[T_Schema] | str,
2211
2240
  reply_to: str | None = None,
2212
2241
  ) -> None:
2213
2242
  """Send response message(s) to user with enhanced error handling and retry logic.
@@ -2255,12 +2284,24 @@ class WhatsAppBot(BaseModel):
2255
2284
  ... reply_to="msg_123"
2256
2285
  ... )
2257
2286
  """
2258
- # Extract text from GeneratedAssistantMessage if needed
2259
- response_text = (
2260
- response.text
2261
- if isinstance(response, GeneratedAssistantMessage)
2262
- else response
2263
- )
2287
+ response_text = ""
2288
+
2289
+ if isinstance(response, GeneratedAssistantMessage):
2290
+ # Check if we have structured output (parsed)
2291
+ if response.parsed:
2292
+ # Use the 'response' field from structured output
2293
+ response_text = response.parsed.response
2294
+ logger.debug(
2295
+ "[SEND_RESPONSE] Using structured output 'response' field "
2296
+ + f"(schema: {type(response.parsed).__name__})"
2297
+ )
2298
+ else:
2299
+ # Fallback to text field
2300
+ response_text = response.text
2301
+ logger.debug("[SEND_RESPONSE] Using standard text response")
2302
+ else:
2303
+ # Direct string
2304
+ response_text = response
2264
2305
 
2265
2306
  # Apply WhatsApp-specific markdown formatting
2266
2307
  response_text = self._format_whatsapp_markdown(response_text)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentle
3
- Version: 0.9.26
3
+ Version: 0.9.28
4
4
  Summary: ...
5
5
  Author-email: Arthur Brenno <64020210+arthurbrenno@users.noreply.github.com>
6
6
  License-File: LICENSE
@@ -78,7 +78,7 @@ agentle/agents/apis/cache_strategy.py,sha256=uoAvmUm1EE8426anuLR4PoygLgO4SPN1Qm_
78
78
  agentle/agents/apis/circuit_breaker.py,sha256=9yopLPoZ6WMlPMWPoacayORoGN1CZq2EGWB0gCu3GOY,2371
79
79
  agentle/agents/apis/circuit_breaker_error.py,sha256=I5XyCWwFCXTDzhvS7CpMZwBRxMyCk96g7MfBLBqAvhg,127
80
80
  agentle/agents/apis/circuit_breaker_state.py,sha256=6IwcWWKNmE0cnpogcfsnhpy_EVIk7crQ7WiDN9YkkbE,277
81
- agentle/agents/apis/endpoint.py,sha256=4skIMje2oEbc6ONb-Ww66wh8VGP5tj1JZACE3p7U62E,22600
81
+ agentle/agents/apis/endpoint.py,sha256=MEaWIGJHK7uq9QZONTf6aGum9ak5gCN8cLqWJ9ltdVE,22657
82
82
  agentle/agents/apis/endpoint_parameter.py,sha256=A_SVje6AyNeeJNDxWL__uGc4ZNZ2se6GvawS--kUYEU,20230
83
83
  agentle/agents/apis/endpoints_to_tools.py,sha256=5KzxRLjfUYx7MGKHe65NMPHyTKOcd8tdK0uYzfGnO5g,999
84
84
  agentle/agents/apis/file_upload.py,sha256=PzJ1197EKLCdBHrLDztgifM3WWFQZ8K2CKkTeeYpJas,587
@@ -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=D51UD2Wbi47RKgxUU8J7iWsxNMqV99Rzujz6TV1DjGw,160179
140
+ agentle/agents/whatsapp/whatsapp_bot.py,sha256=7B1ZCQYMJ6qgRINFzSQVSshDr-4L1F5H3MHqJYI7w3g,161962
141
141
  agentle/agents/whatsapp/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
142
142
  agentle/agents/whatsapp/models/audio_message.py,sha256=kUqG1HdNW6DCYD-CqscJ6WHlAyv9ufmTSKMdjio9XWk,2705
143
143
  agentle/agents/whatsapp/models/context_info.py,sha256=sk80KuNE36S6VRnLh7n6UXmzZCXIB4E4lNxnRyVizg8,563
@@ -146,7 +146,7 @@ agentle/agents/whatsapp/models/device_list_metadata.py,sha256=Nki7esmgi9Zq70L2t4
146
146
  agentle/agents/whatsapp/models/document_message.py,sha256=aZaJCp33GwP1fP5j2DVSWBSVQ4udoE0vj21mc3zjbWQ,2502
147
147
  agentle/agents/whatsapp/models/downloaded_media.py,sha256=TAZEX2oyXp4m4Dk8eRcgoaQCjDyUTN3E6BqkA4pIB9k,204
148
148
  agentle/agents/whatsapp/models/image_message.py,sha256=9inTFNzJq-VJbUaUNzeHfrI7l6Qx7gSM5ydNF0FuRLY,3859
149
- agentle/agents/whatsapp/models/key.py,sha256=s1oU79XSU29VBe0QV2h8Ek86xhqnZMG5te8gkghdmDY,418
149
+ agentle/agents/whatsapp/models/key.py,sha256=BXntl5i2qL110Bja3ZE2INQqC-tf_rone2YU6JVpqbI,434
150
150
  agentle/agents/whatsapp/models/message.py,sha256=HqCqra8vOn3fig53SxnxPgtph20tBEjODlXTLiSErps,1446
151
151
  agentle/agents/whatsapp/models/message_context_info.py,sha256=msCSuu8uMN3G9GDaXdP6mefmOxSjeY-7iL-gN6Q9-i8,741
152
152
  agentle/agents/whatsapp/models/quoted_message.py,sha256=QC4sp7eLPE9g9i-_f3avb0sDO7gKpkzZR2qkbxqptts,1073
@@ -161,6 +161,7 @@ agentle/agents/whatsapp/models/whatsapp_media_message.py,sha256=-FY15vezGILzGMiU
161
161
  agentle/agents/whatsapp/models/whatsapp_message.py,sha256=QtGAJKOF1ykZycsNDld25gk-JUeg3uV7hNXx0ZXO0Rg,1217
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
+ agentle/agents/whatsapp/models/whatsapp_response_base.py,sha256=IIDONx9Ipt593tAZvoc8dPDUISeNH-WOpRP1x_-Q6Gk,1145
164
165
  agentle/agents/whatsapp/models/whatsapp_session.py,sha256=9G1HC-A2G9jTdpwYy3w9bnYkOGK2vvA7kdYAf32oWMU,15640
165
166
  agentle/agents/whatsapp/models/whatsapp_text_message.py,sha256=GpSwFrPC4qpQlVCWKKgYjQJKNv0qvwgYfuoD3ttLzdQ,441
166
167
  agentle/agents/whatsapp/models/whatsapp_video_message.py,sha256=-d-4hnkkxyLVNoje3a1pOEAvzWqoCLFcBn70wUpnyXY,346
@@ -1017,7 +1018,7 @@ agentle/web/actions/scroll.py,sha256=WqVVAORNDK3BL1oASZBPmXJYeSVkPgAOmWA8ibYO82I
1017
1018
  agentle/web/actions/viewport.py,sha256=KCwm88Pri19Qc6GLHC69HsRxmdJz1gEEAODfggC_fHo,287
1018
1019
  agentle/web/actions/wait.py,sha256=IKEywjf-KC4ni9Gkkv4wgc7bY-hk7HwD4F-OFWlyf2w,571
1019
1020
  agentle/web/actions/write_text.py,sha256=9mxfHcpKs_L7BsDnJvOYHQwG8M0GWe61SRJAsKk3xQ8,748
1020
- agentle-0.9.26.dist-info/METADATA,sha256=ZCnSN_aDQlrUPevRNIgjpDU64lRUcusv_5bx3ZcDFP0,86849
1021
- agentle-0.9.26.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1022
- agentle-0.9.26.dist-info/licenses/LICENSE,sha256=T90S9vqRS6qP-voULxAcvwEs558wRRo6dHuZrjgcOUI,1085
1023
- agentle-0.9.26.dist-info/RECORD,,
1021
+ agentle-0.9.28.dist-info/METADATA,sha256=ZY7T2Si68vQ1uj1qjcgtbqbY7XDWEcnvUkOo-pbF7C8,86849
1022
+ agentle-0.9.28.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
1023
+ agentle-0.9.28.dist-info/licenses/LICENSE,sha256=T90S9vqRS6qP-voULxAcvwEs558wRRo6dHuZrjgcOUI,1085
1024
+ agentle-0.9.28.dist-info/RECORD,,