Skip to content

Conversation

@leseb
Copy link
Collaborator

@leseb leseb commented Dec 9, 2025

What does this PR do?

Convert the Conversations API from the legacy @webmethod decorator system to FastAPI routers, following the established pattern from the Batches API.

The only notable difference is that now the conversations API is properly listed when inspecting routes.

Fixes: #4341

Test Plan

Unit and integration tests:

export OPENAI_API_KEY=******
./scripts/integration-tests.sh --stack-config http://localhost:8321 --subdirs conversations --setup gpt

Also, inspect endpoint:

curl http://localhost:8321/v1/inspect/routes | jq '.data[] | select(.route | contains("conversa"))'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 10382  100 10382    0     0   611k      0 --:--:-- --:--:-- --:--:--  633k
{
  "route": "/v1/conversations",
  "method": "POST",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}",
  "method": "GET",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}",
  "method": "POST",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}",
  "method": "DELETE",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}/items",
  "method": "POST",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}/items/{item_id}",
  "method": "GET",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}/items",
  "method": "GET",
  "provider_types": []
}
{
  "route": "/v1/conversations/{conversation_id}/items/{item_id}",
  "method": "DELETE",
  "provider_types": []
}

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Meta Open Source bot. label Dec 9, 2025
@github-actions
Copy link
Contributor

github-actions bot commented Dec 9, 2025

✱ Stainless preview builds

This PR will update the llama-stack-client SDKs with the following commit message.

feat: migrate Conversations API to FastAPI router

Edit this comment to update it. It will appear in the SDK's changelogs.

llama-stack-client-python studio · code · diff

generate ⚠️build ⏳lint ⏳test ⏳

llama-stack-client-node studio · code · diff

Your SDK built successfully.
generate ⚠️build ✅lint ✅test ✅

npm install https://pkg.stainless.com/s/llama-stack-client-node/6e5b87a83db9060e755d8fcc6a6e6c142572254a/dist.tar.gz
llama-stack-client-kotlin studio · code · diff

generate ⚠️lint ⏳test ⏳

llama-stack-client-go studio · code · diff

Your SDK built successfully.
generate ❗lint ❗test ❗

go get github.com/stainless-sdks/llama-stack-client-go@0ccaf9885c0e548472da6aa78d08d17f2985aa85

⏳ These are partial results; builds are still running.


This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
Last updated: 2025-12-17 17:13:03 UTC

@leseb leseb force-pushed the routeur-conversations branch from 0e9e2e2 to 57175d2 Compare December 10, 2025 14:08
@mergify
Copy link

mergify bot commented Dec 14, 2025

This pull request has merge conflicts that must be resolved before it can be merged. @leseb please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify bot added the needs-rebase label Dec 14, 2025
@leseb leseb force-pushed the routeur-conversations branch from 57175d2 to 0173317 Compare December 16, 2025 08:30
@mergify mergify bot removed the needs-rebase label Dec 16, 2025
@ashwinb
Copy link
Contributor

ashwinb commented Dec 16, 2025

Conformance test is RED!

@leseb
Copy link
Collaborator Author

leseb commented Dec 17, 2025

Conformance test is RED!

Yeah but the "breaking change" is actually the spec now correctly reflecting what the API has always returned. The old @webmethod system was likely not properly expanding the Union type in the schema. The old spec showed only OpenAIResponseMessage - this was incomplete. We are still returning ConversationItem, which is a Union type so now the spec correctly shows the oneOf with all possible types.

Previously we had src/llama_stack_api/conversations.py like so:

    @webmethod(route="/conversations/{conversation_id}/items/{item_id}", method="GET", level=LLAMA_STACK_API_V1)
    async def retrieve(self, conversation_id: str, item_id: str) -> ConversationItem:

With the resulting spec:

  /v1/conversations/{conversation_id}/items/{item_id}:
    get:
      responses:
        '200':
          description: The conversation item.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpenAIResponseMessage'

The new code in src/llama_stack_api/conversations/fastapi_routes.py:

    @router.get(
        "/conversations/{conversation_id}/items/{item_id}",
        response_model=ConversationItem,
        summary="Retrieve an item.",
        description="Retrieve a conversation item.",
        responses={200: {"description": "The conversation item."}},
    )
    async def retrieve_item(
        conversation_id: Annotated[str, Path(description="The conversation identifier.")],
        item_id: Annotated[str, Path(description="The item identifier.")],
    ) -> ConversationItem:
        request = RetrieveItemRequest(conversation_id=conversation_id, item_id=item_id)
        return await impl.retrieve(request)

With the resulting spec:

   get:
      responses:
        '200':
          description: The conversation item.
          content:
            application/json:
              schema:
                oneOf:
                - $ref: '#/components/schemas/OpenAIResponseMessage-Output'
                - $ref: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall'
                - $ref: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall'
                - $ref: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall'
                - $ref: '#/components/schemas/OpenAIResponseInputFunctionToolCallOutput'
                - $ref: '#/components/schemas/OpenAIResponseMCPApprovalRequest'
                - $ref: '#/components/schemas/OpenAIResponseMCPApprovalResponse'
                - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPCall'
                - $ref: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools'
                discriminator:
                  propertyName: type
                  mapping:
                    message: '#/components/schemas/OpenAIResponseMessage-Output'
                    web_search_call: '#/components/schemas/OpenAIResponseOutputMessageWebSearchToolCall'
                    file_search_call: '#/components/schemas/OpenAIResponseOutputMessageFileSearchToolCall'
                    function_call: '#/components/schemas/OpenAIResponseOutputMessageFunctionToolCall'
                    function_call_output: '#/components/schemas/OpenAIResponseInputFunctionToolCallOutput'
                    mcp_approval_request: '#/components/schemas/OpenAIResponseMCPApprovalRequest'
                    mcp_approval_response: '#/components/schemas/OpenAIResponseMCPApprovalResponse'
                    mcp_call: '#/components/schemas/OpenAIResponseOutputMessageMCPCall'
                    mcp_list_tools: '#/components/schemas/OpenAIResponseOutputMessageMCPListTools'
                title: Response Retrieve Item V1 Conversations  Conversation Id  Items  Item Id  Get

Reminder for ConversationItem is left unchanged:

ConversationItem = Annotated[
    OpenAIResponseMessage
    | OpenAIResponseOutputMessageWebSearchToolCall
    | OpenAIResponseOutputMessageFileSearchToolCall
    | OpenAIResponseOutputMessageFunctionToolCall
    | OpenAIResponseInputFunctionToolCallOutput
    | OpenAIResponseMCPApprovalRequest
    | OpenAIResponseMCPApprovalResponse
    | OpenAIResponseOutputMessageMCPCall
    | OpenAIResponseOutputMessageMCPListTools
    | OpenAIResponseOutputMessageMCPCall
    | OpenAIResponseOutputMessageMCPListTools,
    Field(discriminator="type"),
]
register_schema(ConversationItem, name="ConversationItem")

This is likely a bug in our generator and another reason why the migration is important :).

The other message like:

error	[response-required-property-removed] at docs/static/llama-stack-spec.yaml	
	in API GET /v1/conversations/{conversation_id}/items/{item_id}
		removed the required property 'content' from the response with the '200' status

This is also a consequence of the Union NOT properly being handled, since we have a oneOf, there's no guarantee that any field is present across all variants.

Makes sense?
Thanks!

@mergify
Copy link

mergify bot commented Dec 17, 2025

This pull request has merge conflicts that must be resolved before it can be merged. @leseb please rebase it. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify bot added the needs-rebase label Dec 17, 2025
Convert the Conversations API from the legacy @webmethod decorator system
to FastAPI routers, following the established pattern from the Batches API.

The only notable difference is that now the conversations API is
properly listed when inspecting routes.

Fixes: llamastack#4341
Signed-off-by: Sébastien Han <seb@redhat.com>
@leseb leseb force-pushed the routeur-conversations branch from c10d251 to f825d6b Compare December 17, 2025 16:36
@mergify mergify bot removed the needs-rebase label Dec 17, 2025
@leseb
Copy link
Collaborator Author

leseb commented Dec 17, 2025

@ashwinb #4342 (comment)

@cdoern
Copy link
Collaborator

cdoern commented Dec 18, 2025

yes, I agree with @leseb 's comment above, this failing conformance seems like a misnomer rather than something to worry about. We might see some of these failures with these router conversions as they "correct" the API types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Convert conversations API to use a FastAPI router

3 participants