mirror of
https://github.com/meta-llama/llama-stack.git
synced 2025-10-18 15:27:16 +00:00
feat(responses)!: improve responses + conversations implementations (#3810)
This PR updates the Conversation item related types and improves a couple critical parts of the implemenation: - it creates a streaming output item for the final assistant message output by the model. until now we only added content parts and included that message in the final response. - rewrites the conversation update code completely to account for items other than messages (tool calls, outputs, etc.) ## Test Plan Used the test script from https://github.com/llamastack/llama-stack-client-python/pull/281 for this ``` TEST_API_BASE_URL=http://localhost:8321/v1 \ pytest tests/integration/test_agent_turn_step_events.py::test_client_side_function_tool -xvs ```
This commit is contained in:
parent
add8cd801b
commit
e9b4278a51
129 changed files with 86266 additions and 903 deletions
|
@ -88,12 +88,20 @@ class ResponsesStore:
|
|||
},
|
||||
)
|
||||
|
||||
await self.sql_store.create_table(
|
||||
"conversation_messages",
|
||||
{
|
||||
"conversation_id": ColumnDefinition(type=ColumnType.STRING, primary_key=True),
|
||||
"messages": ColumnType.JSON,
|
||||
},
|
||||
)
|
||||
|
||||
if self.enable_write_queue:
|
||||
self._queue = asyncio.Queue(maxsize=self._max_write_queue_size)
|
||||
for _ in range(self._num_writers):
|
||||
self._worker_tasks.append(asyncio.create_task(self._worker_loop()))
|
||||
else:
|
||||
logger.info("Write queue disabled for SQLite to avoid concurrency issues")
|
||||
logger.debug("Write queue disabled for SQLite to avoid concurrency issues")
|
||||
|
||||
async def shutdown(self) -> None:
|
||||
if not self._worker_tasks:
|
||||
|
@ -294,3 +302,54 @@ class ResponsesStore:
|
|||
items = items[:limit]
|
||||
|
||||
return ListOpenAIResponseInputItem(data=items)
|
||||
|
||||
async def store_conversation_messages(self, conversation_id: str, messages: list[OpenAIMessageParam]) -> None:
|
||||
"""Store messages for a conversation.
|
||||
|
||||
:param conversation_id: The conversation identifier.
|
||||
:param messages: List of OpenAI message parameters to store.
|
||||
"""
|
||||
if not self.sql_store:
|
||||
raise ValueError("Responses store is not initialized")
|
||||
|
||||
# Serialize messages to dict format for JSON storage
|
||||
messages_data = [msg.model_dump() for msg in messages]
|
||||
|
||||
# Upsert: try insert first, update if exists
|
||||
try:
|
||||
await self.sql_store.insert(
|
||||
table="conversation_messages",
|
||||
data={"conversation_id": conversation_id, "messages": messages_data},
|
||||
)
|
||||
except Exception:
|
||||
# If insert fails due to ID conflict, update existing record
|
||||
await self.sql_store.update(
|
||||
table="conversation_messages",
|
||||
data={"messages": messages_data},
|
||||
where={"conversation_id": conversation_id},
|
||||
)
|
||||
|
||||
logger.debug(f"Stored {len(messages)} messages for conversation {conversation_id}")
|
||||
|
||||
async def get_conversation_messages(self, conversation_id: str) -> list[OpenAIMessageParam] | None:
|
||||
"""Get stored messages for a conversation.
|
||||
|
||||
:param conversation_id: The conversation identifier.
|
||||
:returns: List of OpenAI message parameters, or None if no messages stored.
|
||||
"""
|
||||
if not self.sql_store:
|
||||
raise ValueError("Responses store is not initialized")
|
||||
|
||||
record = await self.sql_store.fetch_one(
|
||||
table="conversation_messages",
|
||||
where={"conversation_id": conversation_id},
|
||||
)
|
||||
|
||||
if record is None:
|
||||
return None
|
||||
|
||||
# Deserialize messages from JSON storage
|
||||
from pydantic import TypeAdapter
|
||||
|
||||
adapter = TypeAdapter(list[OpenAIMessageParam])
|
||||
return adapter.validate_python(record["messages"])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue