| 
19 | 19 | import threading  | 
20 | 20 | import uuid  | 
21 | 21 | from collections import defaultdict  | 
22 |  | -from datetime import datetime  | 
23 | 22 | from pathlib import Path  | 
24 | 23 | from typing import (  | 
25 | 24 |     TYPE_CHECKING,  | 
@@ -509,15 +508,15 @@ def update_memory(  | 
509 | 508 |                 memory record. If None, current timestamp will be used.  | 
510 | 509 |                 (default: :obj:`None`)  | 
511 | 510 |         """  | 
512 |  | -        from datetime import timezone  | 
 | 511 | +        import time  | 
513 | 512 | 
 
  | 
514 | 513 |         self.memory.write_record(  | 
515 | 514 |             MemoryRecord(  | 
516 | 515 |                 message=message,  | 
517 | 516 |                 role_at_backend=role,  | 
518 | 517 |                 timestamp=timestamp  | 
519 | 518 |                 if timestamp is not None  | 
520 |  | -                else datetime.now(timezone.utc).timestamp(),  | 
 | 519 | +                else time.time_ns() / 1_000_000_000,  # Nanosecond precision  | 
521 | 520 |                 agent_id=self.agent_id,  | 
522 | 521 |             )  | 
523 | 522 |         )  | 
@@ -1331,6 +1330,13 @@ def _handle_batch_response(  | 
1331 | 1330 |         """  | 
1332 | 1331 |         output_messages: List[BaseMessage] = []  | 
1333 | 1332 |         for choice in response.choices:  | 
 | 1333 | +            # Skip messages with no meaningful content  | 
 | 1334 | +            if (  | 
 | 1335 | +                choice.message.content is None  | 
 | 1336 | +                or choice.message.content.strip() == ""  | 
 | 1337 | +            ) and not choice.message.tool_calls:  | 
 | 1338 | +                continue  | 
 | 1339 | + | 
1334 | 1340 |             meta_dict = {}  | 
1335 | 1341 |             if logprobs_info := handle_logprobs(choice):  | 
1336 | 1342 |                 meta_dict["logprobs_info"] = logprobs_info  | 
@@ -1623,17 +1629,24 @@ def _record_tool_calling(  | 
1623 | 1629 |             tool_call_id=tool_call_id,  | 
1624 | 1630 |         )  | 
1625 | 1631 | 
 
  | 
1626 |  | -        # Use slightly different timestamps to ensure correct ordering  | 
 | 1632 | +        # Use precise timestamps to ensure correct ordering  | 
1627 | 1633 |         # This ensures the assistant message (tool call) always appears before  | 
1628 | 1634 |         # the function message (tool result) in the conversation context  | 
1629 |  | -        current_time = datetime.now().timestamp()  | 
 | 1635 | +        # Use time.time_ns() for nanosecond precision to avoid collisions  | 
 | 1636 | +        import time  | 
 | 1637 | + | 
 | 1638 | +        current_time_ns = time.time_ns()  | 
 | 1639 | +        base_timestamp = current_time_ns / 1_000_000_000  # Convert to seconds  | 
 | 1640 | + | 
1630 | 1641 |         self.update_memory(  | 
1631 |  | -            assist_msg, OpenAIBackendRole.ASSISTANT, timestamp=current_time  | 
 | 1642 | +            assist_msg, OpenAIBackendRole.ASSISTANT, timestamp=base_timestamp  | 
1632 | 1643 |         )  | 
 | 1644 | + | 
 | 1645 | +        # Add minimal increment to ensure function message comes after  | 
1633 | 1646 |         self.update_memory(  | 
1634 | 1647 |             func_msg,  | 
1635 | 1648 |             OpenAIBackendRole.FUNCTION,  | 
1636 |  | -            timestamp=current_time + 0.001,  | 
 | 1649 | +            timestamp=base_timestamp + 1e-9,  | 
1637 | 1650 |         )  | 
1638 | 1651 | 
 
  | 
1639 | 1652 |         # Record information about this tool call  | 
 | 
0 commit comments