Query using Letta's official agent API. Sends the question to the Letta agent which will use its internal archival_memory_search tool to retrieve relevant memories and respond. Question is truncated if exceeding max_question_tokens.
(
self,
question: str,
system_message: Optional[str] = None,
**kwargs,
)
| 558 | ) |
| 559 | |
| 560 | def query( |
| 561 | self, |
| 562 | question: str, |
| 563 | system_message: Optional[str] = None, |
| 564 | **kwargs, |
| 565 | ) -> AgentResponse: |
| 566 | """Query using Letta's official agent API. |
| 567 | |
| 568 | Sends the question to the Letta agent which will use its internal |
| 569 | archival_memory_search tool to retrieve relevant memories and respond. |
| 570 | |
| 571 | Question is truncated if exceeding max_question_tokens. |
| 572 | """ |
| 573 | context_id = self._get_context_id() |
| 574 | agent_id = self._ensure_agent(context_id) |
| 575 | |
| 576 | # Truncate question if needed |
| 577 | bounded_question = self._truncate_to_tokens(question, self.max_question_tokens) |
| 578 | |
| 579 | # Build query message |
| 580 | if system_message: |
| 581 | query_message = f"{system_message}\n\nQuestion: {bounded_question}" |
| 582 | else: |
| 583 | query_message = bounded_question |
| 584 | |
| 585 | start_time = time.time() |
| 586 | try: |
| 587 | # Switch to restricted context_window for query phase (token budget truncation) |
| 588 | # Only update once per agent (build phase is always completed before query phase) |
| 589 | if self.max_context_tokens and self.max_context_tokens < self.context_window: |
| 590 | if not getattr(self, '_query_context_applied', {}).get(agent_id): |
| 591 | query_llm_config = self._build_llm_config().model_copy( |
| 592 | update={"context_window": self.max_context_tokens} |
| 593 | ) |
| 594 | self._client.update_agent(agent_id, llm_config=query_llm_config) |
| 595 | if not hasattr(self, '_query_context_applied'): |
| 596 | self._query_context_applied = {} |
| 597 | self._query_context_applied[agent_id] = True |
| 598 | |
| 599 | response = self._client.user_message(agent_id=agent_id, message=query_message) |
| 600 | query_time = time.time() - start_time |
| 601 | except Exception as e: |
| 602 | logger.error(f"Letta user_message failed: {e}") |
| 603 | return AgentResponse( |
| 604 | output=f"[Error: {e}]", |
| 605 | query_time=0.0, |
| 606 | retrieved_count=0, |
| 607 | extra={ |
| 608 | "method": "letta", |
| 609 | "agent_id": agent_id, |
| 610 | "error": str(e), |
| 611 | }, |
| 612 | ) |
| 613 | |
| 614 | parsed = self._parse_letta_response(response) |
| 615 | self._record_usage_to_tracker(parsed, "query", query_time) |
| 616 | |
| 617 | # Extract retrieved memories from search function calls |
nothing calls this directly
no test coverage detected