Run the deep-agents loop for *question*. Args: question: Natural-language question to answer. Returns: :class:`AgentResult` with the final answer and full trajectory.
(self, question: str)
| 173 | return _build_chat_model(self._model_id) |
| 174 | |
| 175 | async def run(self, question: str) -> AgentResult: |
| 176 | """Run the deep-agents loop for *question*. |
| 177 | |
| 178 | Args: |
| 179 | question: Natural-language question to answer. |
| 180 | |
| 181 | Returns: |
| 182 | :class:`AgentResult` with the final answer and full trajectory. |
| 183 | """ |
| 184 | with agent_run_span( |
| 185 | "deep-agent", model=self._model_id, question=question |
| 186 | ) as span: |
| 187 | run_started = time.perf_counter() |
| 188 | started_at = _dt.datetime.now(_dt.UTC).isoformat() |
| 189 | from deepagents import create_deep_agent |
| 190 | from langchain_mcp_adapters.client import MultiServerMCPClient |
| 191 | |
| 192 | connections = _build_mcp_connections(self._server_paths) |
| 193 | client = MultiServerMCPClient(connections) if connections else None |
| 194 | tools = await client.get_tools() if client is not None else [] |
| 195 | |
| 196 | agent = create_deep_agent( |
| 197 | model=self._chat_model, |
| 198 | tools=tools, |
| 199 | system_prompt=AGENT_SYSTEM_PROMPT, |
| 200 | ) |
| 201 | |
| 202 | _log.info( |
| 203 | "DeepAgentRunner: starting query (model=%s, tools=%d)", |
| 204 | self._model_id, |
| 205 | len(tools), |
| 206 | ) |
| 207 | |
| 208 | state = await agent.ainvoke( |
| 209 | {"messages": [{"role": "user", "content": question}]}, |
| 210 | config={"recursion_limit": self._recursion_limit}, |
| 211 | ) |
| 212 | |
| 213 | messages = state.get("messages", []) if isinstance(state, dict) else [] |
| 214 | trajectory = _build_trajectory(messages) |
| 215 | trajectory.started_at = started_at |
| 216 | |
| 217 | answer = "" |
| 218 | for msg in reversed(messages): |
| 219 | if isinstance(msg, AIMessage): |
| 220 | if isinstance(msg.content, str) and msg.content.strip(): |
| 221 | answer = msg.content |
| 222 | break |
| 223 | if isinstance(msg.content, list): |
| 224 | parts = [ |
| 225 | p.get("text", "") |
| 226 | for p in msg.content |
| 227 | if isinstance(p, dict) and p.get("type") == "text" |
| 228 | ] |
| 229 | joined = "".join(parts).strip() |
| 230 | if joined: |
| 231 | answer = joined |
| 232 | break |