Skip to content

Commit 8f164b7

Browse files
committed
Address PR review comments
- Fix docstring in workflow_hitl_tool_approval.py to match implementation - Replace json.dumps with Jsonb adapter in workflow_hitl_checkpoint_pg.py - Move WorkflowCheckpoint to public import path - Translate tool docstrings to Spanish in spanish/ examples - Translate 'goodbye' termination to Spanish in workflow_hitl_handoff.py - Fix run command filename in workflow_hitl_requests.py - Remove misleading 'exit' from prompts in workflow_hitl_requests_structured.py - Update AGENTS.md to clarify @tool docstring translation rule
1 parent b16b147 commit 8f164b7

10 files changed

Lines changed: 34 additions & 24 deletions

AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,11 @@ Each example .py file should have a corresponding file with the same name under
3232
* Comments: Spanish
3333
* Docstrings: Spanish
3434
* System prompts (agent instructions): Spanish
35-
* Tool descriptions (metadata like description=): English
36-
* Parameter descriptions (Field(description=...)): English
3735
* Identifiers (functions/classes/vars): English
3836
* User-facing output/data (e.g., example responses, sample values): Spanish
37+
* @tool function names: English
38+
* @tool parameter descriptions (Field(description=...)): English
39+
* @tool docstrings: Spanish
3940
* HITL control words: bilingual (approve/aprobar, exit/salir)
4041
* Agent and workflow names: English ("TravelPlannerAgent" should be the same in both versions, not "AgentePlanificadorDeViajes")
4142

examples/spanish/agent_tool_approval.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
def lookup_receipt(
6363
receipt_id: Annotated[str, "The receipt ID to look up"],
6464
) -> dict[str, str]:
65-
"""Look up a receipt by ID and return its details."""
65+
"""Busca un recibo por ID y devuelve sus detalles."""
6666
return receipts_db.get(receipt_id, {"error": f"Recibo {receipt_id} no encontrado"})
6767

6868

@@ -72,7 +72,7 @@ def submit_expense_report(
7272
total_amount: Annotated[str, "Total amount to reimburse"],
7373
receipt_ids: Annotated[str, "Comma-separated receipt IDs included"],
7474
) -> str:
75-
"""Submit an expense report for reimbursement. Requires manager approval."""
75+
"""Envía un reporte de gastos para reembolso. Requiere aprobación del gerente."""
7676
report = {"description": description, "total_amount": total_amount, "receipt_ids": receipt_ids}
7777
submitted_reports.append(report)
7878
return f"Reporte de gastos enviado: {description} por {total_amount} (recibos: {receipt_ids})"

examples/spanish/workflow_hitl_checkpoint_pg.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
"""
1010

1111
import asyncio
12-
import json
1312
import os
1413
from dataclasses import dataclass
1514
from typing import Any
1615

1716
import psycopg
17+
from psycopg.types.json import Jsonb
1818
from agent_framework import (
1919
Agent,
2020
AgentExecutor,
@@ -28,7 +28,10 @@
2828
handler,
2929
response_handler,
3030
)
31-
from agent_framework._workflows._checkpoint import WorkflowCheckpoint
31+
from agent_framework import WorkflowCheckpoint
32+
33+
# Importación privada — aún no hay API pública para la codificación de checkpoints.
34+
# Ver: https://github.com/microsoft/agent-framework/issues/4428
3235
from agent_framework._workflows._checkpoint_encoding import decode_checkpoint_value, encode_checkpoint_value
3336
from agent_framework.exceptions import WorkflowCheckpointException
3437
from agent_framework.openai import OpenAIChatClient
@@ -79,7 +82,7 @@ async def save(self, checkpoint: WorkflowCheckpoint) -> str:
7982
VALUES (%s, %s, %s, %s)
8083
ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data""",
8184
(checkpoint.checkpoint_id, checkpoint.workflow_name,
82-
checkpoint.timestamp, json.dumps(encoded)),
85+
checkpoint.timestamp, Jsonb(encoded)),
8386
)
8487
return checkpoint.checkpoint_id
8588

examples/spanish/workflow_hitl_handoff.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ def process_return(
5555
order_number: Annotated[str, "The 3-digit order number"],
5656
return_type: Annotated[str, "Either 'refund' or 'replacement'"],
5757
) -> str:
58-
"""Process a product return for the given order."""
59-
return f"Return processed for order {order_number}: {return_type} approved. Confirmation email sent."
58+
"""Procesa una devolución de producto para el pedido indicado."""
59+
return f"Devolución procesada para el pedido {order_number}: {return_type} aprobado. Correo de confirmación enviado."
6060

6161

6262
# --- Agentes ---
@@ -107,7 +107,8 @@ def process_return(
107107
name="customer_support",
108108
participants=[triage_agent, order_agent, return_agent],
109109
termination_condition=lambda conversation: (
110-
len(conversation) > 0 and "goodbye" in conversation[-1].text.lower()
110+
len(conversation) > 0
111+
and any(word in conversation[-1].text.lower() for word in ("adiós", "adios", "chao"))
111112
),
112113
)
113114
.with_start_agent(triage_agent)

examples/spanish/workflow_hitl_requests_structured.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ async def main() -> None:
187187

188188
for request_id, request in pending.items():
189189
print(f"\n⏸️ El agente pregunta: {request.message}")
190-
answer = input("💬 Tu respuesta (o 'exit/salir'): ")
190+
answer = input("💬 Tu respuesta: ")
191191
pending[request_id] = answer
192192

193193
stream = workflow.run(stream=True, responses=pending)

examples/spanish/workflow_hitl_tool_approval.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Workflow de agente de correo con aprobación de herramientas para operaciones sensibles.
22
3-
Demuestra: @tool(approval_mode="always_require"), FunctionApprovalRequestContent,
4-
to_function_approval_response(), y un bucle de eventos que maneja solicitudes de aprobación.
3+
Demuestra: @tool(approval_mode="always_require"), verificación de tipo Content
4+
con data.type == "function_approval_request", to_function_approval_response(),
5+
y un bucle de eventos que maneja solicitudes de aprobación via get_request_info_events().
56
67
Un agente de redacción de correos procesa correos entrantes y usa herramientas para
78
buscar contexto y enviar respuestas. Herramientas como send_email y read_historical_email_data
@@ -65,13 +66,13 @@
6566

6667
@tool(approval_mode="never_require")
6768
def get_current_date() -> str:
68-
"""Get the current date in YYYY-MM-DD format."""
69+
"""Obtiene la fecha actual en formato YYYY-MM-DD."""
6970
return "2026-03-05"
7071

7172

7273
@tool(approval_mode="never_require")
7374
def get_team_members_email_addresses() -> list[dict[str, str]]:
74-
"""Get the email addresses of team members."""
75+
"""Obtiene las direcciones de correo de los miembros del equipo."""
7576
return [
7677
{"name": "Alice", "email": "alice@contoso.com", "position": "Ingeniera de Software"},
7778
{"name": "Bob", "email": "bob@contoso.com", "position": "Gerente de Producto"},
@@ -85,7 +86,7 @@ async def read_historical_email_data(
8586
start_date: Annotated[str, "The start date in YYYY-MM-DD format"],
8687
end_date: Annotated[str, "The end date in YYYY-MM-DD format"],
8788
) -> list[dict[str, str]]:
88-
"""Read historical email data for a given email address and date range."""
89+
"""Lee datos históricos de correo para una dirección y rango de fechas."""
8990
historical_data = {
9091
"alice@contoso.com": [
9192
{
@@ -119,7 +120,7 @@ async def send_email(
119120
subject: Annotated[str, "The email subject"],
120121
body: Annotated[str, "The email body"],
121122
) -> str:
122-
"""Send an email."""
123+
"""Envía un correo electrónico."""
123124
await asyncio.sleep(0.5) # Simula el envío
124125
return "Correo enviado exitosamente."
125126

examples/workflow_hitl_checkpoint_pg.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
"""
1010

1111
import asyncio
12-
import json
1312
import os
1413
from dataclasses import dataclass
1514
from typing import Any
1615

1716
import psycopg
17+
from psycopg.types.json import Jsonb
1818
from agent_framework import (
1919
Agent,
2020
AgentExecutor,
@@ -28,7 +28,10 @@
2828
handler,
2929
response_handler,
3030
)
31-
from agent_framework._workflows._checkpoint import WorkflowCheckpoint
31+
from agent_framework import WorkflowCheckpoint
32+
33+
# Private import — no public API for checkpoint encoding yet.
34+
# See: https://github.com/microsoft/agent-framework/issues/4428
3235
from agent_framework._workflows._checkpoint_encoding import decode_checkpoint_value, encode_checkpoint_value
3336
from agent_framework.exceptions import WorkflowCheckpointException
3437
from agent_framework.openai import OpenAIChatClient
@@ -79,7 +82,7 @@ async def save(self, checkpoint: WorkflowCheckpoint) -> str:
7982
VALUES (%s, %s, %s, %s)
8083
ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data""",
8184
(checkpoint.checkpoint_id, checkpoint.workflow_name,
82-
checkpoint.timestamp, json.dumps(encoded)),
85+
checkpoint.timestamp, Jsonb(encoded)),
8386
)
8487
return checkpoint.checkpoint_id
8588

examples/workflow_hitl_requests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
This is the minimal HITL pattern — every agent response triggers a human turn.
99
1010
Run:
11-
uv run examples/workflow_hitl_chat.py
11+
uv run examples/workflow_hitl_requests.py
1212
"""
1313

1414
import asyncio

examples/workflow_hitl_requests_structured.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ async def main() -> None:
187187

188188
for request_id, request in pending.items():
189189
print(f"\n⏸️ Agent asks: {request.message}")
190-
answer = input("💬 Your answer (or 'exit'): ")
190+
answer = input("💬 Your answer: ")
191191
pending[request_id] = answer
192192

193193
stream = workflow.run(stream=True, responses=pending)

examples/workflow_hitl_tool_approval.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Email agent workflow with tool approval for sensitive operations.
22
3-
Demonstrates: @tool(approval_mode="always_require"), FunctionApprovalRequestContent,
4-
to_function_approval_response(), and an event loop that handles approval requests.
3+
Demonstrates: @tool(approval_mode="always_require"), Content type checking
4+
with data.type == "function_approval_request", to_function_approval_response(),
5+
and an event loop that handles approval requests via get_request_info_events().
56
67
An email-writing agent processes incoming emails and uses tools to look up
78
context and send replies. Tools like send_email and read_historical_email_data

0 commit comments

Comments
 (0)