refactor: separa composição OCI e inicialização do DeepAgents

This commit is contained in:
alex alves
2026-11-05 16:39:01 -03:00
parent 85fc4c4d46
commit e319b4089c
10 changed files with 508 additions and 153 deletions

View File

@@ -2,10 +2,11 @@
Deep Agents implementation of the AgentVoice Agent port.
Responsibilities:
- OCI Generative AI inference through LangChain.
- Translate a prepared DeepAgents graph to the Agent streaming contract.
- Contextual memory per session.
- Text streaming compatible with VoicePipeline.
- Asynchronous resource cleanup.
- Explicit closure of consumed event streams.
- Model/client ownership belongs to the composition that supplies the graph.
Does not manage:
- WebSocket connections.
@@ -21,27 +22,22 @@ from collections.abc import AsyncGenerator, Iterator
from typing import Any
from contextlib import aclosing
from deepagents import create_deep_agent
from langchain_core.messages import HumanMessage
from langchain_core.runnables import RunnableConfig
from langchain_oci import ChatOCIGenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.state import CompiledStateGraph
from voice_assistant.agent.adapter import StreamingAgentAdapter
DEFAULT_SYSTEM_PROMPT = """
Você é o AgentVoice, um assistente pessoal por voz. Que responde pelo nome de Roberta.
Responda em português brasileiro, de forma natural,
objetiva e adequada para reprodução por voz.
Mantenha o contexto das mensagens anteriores.
Interprete correções e complementos do usuário
considerando o histórico da conversa.
Não invente informações atuais ou resultados
de ferramentas que não foram executadas.
"""
def positive_timeout(value: float, name: str) -> float:
if (
isinstance(value, bool)
or not isinstance(value, (int, float))
or not math.isfinite(value)
or value <= 0
):
raise ValueError(f"{name} must be finite and positive.")
return float(value)
def _text_fragments(content: str | list[str | dict[str, Any]]) -> Iterator[str]:
@@ -62,64 +58,11 @@ def _text_fragments(content: str | list[str | dict[str, Any]]) -> Iterator[str]:
class DeepAgentsAdapter(StreamingAgentAdapter):
def __init__(
self,
region: str,
compartment_id: str,
model_id: str,
temperature: float,
max_completion_tokens: int,
timeout_seconds: float,
system_prompt: str = DEFAULT_SYSTEM_PROMPT,
*,
auth_type: str = "INSTANCE_PRINCIPAL",
auth_profile: str = "DEFAULT",
auth_file_location: str = "~/.oci/config",
) -> None:
if not region:
raise ValueError("OCI region is required.")
if not compartment_id:
raise ValueError("OCI compartment_id is required.")
if not model_id:
raise ValueError("OCI model_id is required.")
if (
isinstance(timeout_seconds, bool)
or not isinstance(timeout_seconds, (int, float))
or not math.isfinite(timeout_seconds)
or timeout_seconds <= 0
):
raise ValueError("timeout_seconds must be finite and positive.")
self._stream_event_timeout = float(timeout_seconds)
self._model = ChatOCIGenAI(
model_id=model_id,
compartment_id=compartment_id,
service_endpoint=(
f"https://inference.generativeai.{region}.oci.oraclecloud.com"
),
auth_type=auth_type,
auth_profile=auth_profile,
auth_file_location=auth_file_location,
is_stream=True,
model_kwargs={
"temperature": temperature,
"max_tokens": max_completion_tokens,
},
def __init__(self, graph: CompiledStateGraph, timeout_seconds: float) -> None:
self._stream_event_timeout = positive_timeout(
timeout_seconds, "timeout_seconds"
)
self._checkpointer = MemorySaver()
self._graph = create_deep_agent(
model=self._model,
tools=[],
system_prompt=system_prompt,
checkpointer=self._checkpointer,
)
self._graph = graph
self._closed = False
@staticmethod
@@ -176,5 +119,4 @@ class DeepAgentsAdapter(StreamingAgentAdapter):
if self._closed:
return
await self._model.aclose()
self._closed = True