Skip to content

Conversation

@tisnik
Copy link
Contributor

@tisnik tisnik commented Jan 12, 2026

Description

LCORE-1169: Up to date OpenAPI documentation

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement

Tools used to create PR

  • Assisted-by: N/A
  • Generated by: N/A

Related Tickets & Documents

  • Related Issue #LCORE-1169

Summary by CodeRabbit

  • New Features

    • Introduced /v1/infer endpoint for stateless inference requests
    • Added agent card endpoints for agent manifest discovery
    • Added A2A protocol integration endpoints
    • Expanded security scheme support including API key, OAuth2, OpenID Connect, and mutual TLS authentication
  • Documentation

    • Comprehensive OpenAPI specification update with new schemas and data models
    • Updated API documentation with detailed request/response examples and error mappings

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

Walkthrough

This PR expands the OpenAPI specification with a new POST /v1/infer endpoint and introduces over 50 new schema definitions for RLS API v1 models, agent card structures, multiple security schemes (API key, HTTP auth, OAuth2, OpenID Connect, mTLS), and various configuration and response models.

Changes

Cohort / File(s) Summary
OpenAPI Schema Definition
docs/openapi.json
Added POST /v1/infer endpoint with request/response contracts. Introduced comprehensive schema components: RlsapiV1InferRequest/Response, RlsapiV1Attachment/CLA/Context/SystemInfo/Terminal, AgentCard/AgentCardSignature/AgentCapabilities/AgentExtension/AgentInterface/AgentProvider/AgentSkill. Added security schemes: APIKeySecurityScheme, HTTPAuthSecurityScheme, OAuth2SecurityScheme, OpenIdConnectSecurityScheme, and OAuth flow definitions (AuthorizationCode, ClientCredentials, Implicit, Password). Included operational schemas: NotFoundResponse, UnprocessableEntityResponse, ModelContextProtocolServer, A2AStateConfiguration.
API Documentation
docs/openapi.md
Expanded documentation with new endpoint descriptions for POST /v1/infer, GET /.well-known/agent-card.json, GET /.well-known/agent.json, and A2A protocol integration. Added comprehensive documentation sections for newly introduced schemas covering RLS API v1 models, agent card definitions, security configurations, and service configuration extensions (base_url, agent_card_path).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

  • #902: Implements the FastAPI endpoint and router for /v1/infer with request/response models that correspond to the schemas defined in this PR.
  • #451: Modifies and adds the same OpenAPI schema entities (AccessRule, Action, AuthorizationConfiguration) and security-related definitions.
  • #647: Modifies OpenAPI documentation and introduces overlapping API schema surfaces (ProvidersListResponse, ByokRag, configuration models).

Suggested labels

ok-to-test

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately references the ticket (LCORE-1169) and describes the main change—updating OpenAPI documentation to be current. However, it lacks specificity about what aspects of the API documentation were expanded.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @docs/openapi.json:
- Around line 8116-8148: Update the RlsapiV1SystemInfo schema description to
reference the actual field name "id" instead of "system_id", and fix the
RlsapiV1Context attachments inconsistency by either renaming the property
"attachments" to "attachment" to match the single RlsapiV1Attachment schema or
by changing the "attachments" property to be an array (type: "array", items: {
"$ref": "#/components/schemas/RlsapiV1Attachment" }) and updating its
description accordingly; apply the same change wherever RlsapiV1Context and
RlsapiV1SystemInfo appear (also at the later block around the other occurrence).
- Around line 3554-3695: Update the 422 response examples for the /v1/infer
operation to reflect RlsapiV1InferRequest: change the "missing attributes"
example to reference only ['question'], fix the typo "attatchment" →
"attachment" in the "invalid value" example, and update that message to state
validation is against attachment mimetype (e.g., "Invalid attachment mimetype:
must be one of [...]") instead of the generic "attachment type" so examples
accurately mirror the infer endpoint's validation behavior.
- Around line 4101-4137: The OpenAPI has duplicate operationId
"handle_a2a_jsonrpc_a2a_post" for the "/a2a" GET and POST entries which breaks
tooling; fix by assigning unique operationIds (e.g.,
"handle_a2a_jsonrpc_a2a_get" for GET and keep "handle_a2a_jsonrpc_a2a_post" for
POST) either by updating the generated docs/openapi.json fragment or by adding
explicit operation_id values when registering the route (the
@router.api_route("/a2a", methods=["GET","POST"]) registration) so the GET and
POST operations have distinct operationId values.
- Around line 4025-4053: The OpenAPI for the /metrics endpoint incorrectly
includes "text/plain" response entries that reference JSON schemas (e.g.,
InternalServerErrorResponse, ServiceUnavailableResponse) even though the
exception handler returns JSON; update the 401/403/500/503 responses to either
remove the "text/plain" content type entirely or replace each "text/plain"
schema with a plain string schema (type: string) to reflect actual plain-text
responses for successful /metrics only, ensuring consistency with
response_class=PlainTextResponse and keeping the JSON "application/json" error
examples intact.

In @docs/openapi.md:
- Line 3192: Replace the misspelled token "attatchment" with the correct
spelling "attachment" wherever it appears in the OpenAPI error message examples
(i.e., update the literal string "attatchment" to "attachment" across all
occurrences in the document). Ensure you update every example response/example
text that contains the exact token "attatchment" so the error messages
consistently read "attachment".
🧹 Nitpick comments (4)
docs/openapi.md (2)

3121-3121: Fix table formatting: missing trailing pipe

The table row is missing a trailing pipe character, which is inconsistent with the rest of the document's table formatting.

📝 Proposed fix
-| 200 | Successful response | [RlsapiV1InferResponse](#rlsapiv1inferresponse) |
+| 200 | Successful response | [RlsapiV1InferResponse](#rlsapiv1inferresponse) |

Note: The trailing pipe should be added after the last column.

Based on static analysis hints.


3560-3560: Add blank lines around tables for consistent formatting

Multiple tables are missing blank lines before and after them, which is inconsistent with Markdown best practices and the rest of this document.

📝 Example fix for line 3560
 | 200 | Successful Response | [AgentCard](#agentcard) |
+
 ## GET `/.well-known/agent.json`

Apply similar fixes to add blank lines around tables at lines 3581, 3613, 3645, and 3663.

Based on static analysis hints.

Also applies to: 3581-3581, 3613-3613, 3645-3645, 3663-3663

docs/openapi.json (2)

8356-8367: Nice additions: service.base_url (A2A) and configuration.a2a_state improve deployability clarity.
Consider adding format: uri for base_url to improve client validation.

Optional tweak
                     "base_url": {
                         "anyOf": [
                             {
                                 "type": "string"
+                                ,"format": "uri"
                             },

Also applies to: 5294-5298


4263-4270: Static analysis: consider maxItems on large/unbounded arrays (RBAC actions).
Not strictly required for OpenAPI, but adding bounds can help validators and client-side UX (esp. if these arrays are user-provided).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 077b10e and 7c5e7d3.

📒 Files selected for processing (2)
  • docs/openapi.json
  • docs/openapi.md
🧰 Additional context used
🪛 Checkov (3.2.334)
docs/openapi.json

[medium] 4263-4270: Ensure that arrays have a maximum number of items

(CKV_OPENAPI_21)

🪛 markdownlint-cli2 (0.18.1)
docs/openapi.md

3121-3121: Table pipe style
Expected: leading_and_trailing; Actual: leading_only; Missing trailing pipe

(MD055, table-pipe-style)


3560-3560: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


3581-3581: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


3613-3613: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


3645-3645: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)


3663-3663: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build-pr
  • GitHub Check: E2E: library mode / ci
  • GitHub Check: E2E: server mode / ci
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-on-pull-request
🔇 Additional comments (5)
docs/openapi.md (4)

3540-3581: Verify duplicate agent card endpoints

Both GET /.well-known/agent-card.json and GET /.well-known/agent.json have identical descriptions and return the same AgentCard response. Are these intentionally duplicated for compatibility purposes, or should they have different descriptions explaining when to use each endpoint?

If these are alternative paths to the same resource (e.g., for backward compatibility or A2A protocol compliance), consider adding a note to clarify this relationship.


3670-4030: LGTM: Well-documented A2A and security schema definitions

The new schema definitions for A2A protocol state configuration, security schemes (API Key, HTTP Auth, OAuth2, OpenID Connect, mTLS), and agent card structures are comprehensive and well-documented. The descriptions clearly explain the purpose of each schema and its attributes.


4227-4228: LGTM: Configuration fields for A2A protocol support

The additions to Customization (agent_card_path, agent_card_config) and ServiceConfiguration (base_url) properly support A2A protocol functionality. The base_url field is correctly described as needed for A2A support, and the agent card customization options provide the necessary flexibility for agent configuration.

Also applies to: 5158-5158


4979-5124: LGTM: Complete RLS API v1 schema definitions

The RHEL Lightspeed RLS API v1 schemas are comprehensively documented with clear descriptions and examples. The naming conventions are consistent (RlsapiV1* prefix), and all required attributes are properly described. The schemas properly support the new POST /v1/infer endpoint.

docs/openapi.json (1)

8321-8340: SecurityScheme objects are correctly used as AgentCard metadata models.

The SecurityScheme schema (lines 8321–8340) is appropriately placed in components.schemas since it serves as a data model for the AgentCard's securitySchemes property—not as an OpenAPI-level security scheme declaration. The specification contains no root-level components.securitySchemes or endpoint-level security requirements; the security and securitySchemes properties at lines 4478 and 4511 are exclusively metadata fields within the AgentCard schema itself. No refactoring needed.

Comment on lines +3554 to +3695
"/v1/infer": {
"post": {
"tags": [
"rlsapi-v1"
],
"summary": "Infer Endpoint",
"description": "Handle rlsapi v1 /infer requests for stateless inference.\n\nThis endpoint serves requests from the RHEL Lightspeed Command Line Assistant (CLA).\n\nAccepts a question with optional context (stdin, attachments, terminal output,\nsystem info) and returns an LLM-generated response.\n\nArgs:\n infer_request: The inference request containing question and context.\n auth: Authentication tuple from the configured auth provider.\n\nReturns:\n RlsapiV1InferResponse containing the generated response text and request ID.\n\nRaises:\n HTTPException: 503 if the LLM service is unavailable.",
"operationId": "infer_endpoint_v1_infer_post",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RlsapiV1InferRequest"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/RlsapiV1InferResponse"
},
"example": {
"data": {
"request_id": "01JDKR8N7QW9ZMXVGK3PB5TQWZ",
"text": "To list files in Linux, use the `ls` command."
}
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnauthorizedResponse"
},
"examples": {
"missing header": {
"value": {
"detail": {
"cause": "No Authorization header found",
"response": "Missing or invalid credentials provided by client"
}
}
},
"missing token": {
"value": {
"detail": {
"cause": "No token found in Authorization header",
"response": "Missing or invalid credentials provided by client"
}
}
}
}
}
}
},
"403": {
"description": "Permission denied",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ForbiddenResponse"
},
"examples": {
"endpoint": {
"value": {
"detail": {
"cause": "User 6789 is not authorized to access this endpoint.",
"response": "User does not have permission to access this endpoint"
}
}
}
}
}
}
},
"422": {
"description": "Request validation failed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UnprocessableEntityResponse"
},
"examples": {
"invalid format": {
"value": {
"detail": {
"cause": "Invalid request format. The request body could not be parsed.",
"response": "Invalid request format"
}
}
},
"missing attributes": {
"value": {
"detail": {
"cause": "Missing required attributes: ['query', 'model', 'provider']",
"response": "Missing required attributes"
}
}
},
"invalid value": {
"value": {
"detail": {
"cause": "Invalid attatchment type: must be one of ['text/plain', 'application/json', 'application/yaml', 'application/xml']",
"response": "Invalid attribute value"
}
}
}
}
}
}
},
"503": {
"description": "Service unavailable",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ServiceUnavailableResponse"
},
"examples": {
"llama stack": {
"value": {
"detail": {
"cause": "Connection error while trying to reach backend service.",
"response": "Unable to connect to Llama Stack"
}
}
}
}
}
}
}
}
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for RlsapiV1InferRequest schema definition in the OpenAPI spec
rg -n 'RlsapiV1InferRequest|RlsapiV1QueryRequest' docs/openapi.json | head -20

Repository: lightspeed-core/lightspeed-stack

Length of output: 208


🏁 Script executed:

#!/bin/bash
# Look for the actual schema definitions
rg -n '"RlsapiV1InferRequest"' docs/openapi.json -A 30

Repository: lightspeed-core/lightspeed-stack

Length of output: 3476


🏁 Script executed:

#!/bin/bash
# Check the /v1/query endpoint 422 examples for comparison
rg -n '"/v1/query"' docs/openapi.json -A 150 | grep -A 50 '"422"'

Repository: lightspeed-core/lightspeed-stack

Length of output: 58


🏁 Script executed:

#!/bin/bash
# Search for the actual inference request handling code
find . -type f \( -name "*.py" -o -name "*.ts" -o -name "*.js" \) | xargs rg -l 'RlsapiV1InferRequest|infer_endpoint' 2>/dev/null | head -10

Repository: lightspeed-core/lightspeed-stack

Length of output: 289


🏁 Script executed:

#!/bin/bash
# Find /v1/query endpoint in openapi.json
rg -n '"/v1/query"' docs/openapi.json -A 200 | grep -E '("/v1/query"|"422"|"query"|"model"|"provider")' | head -30

Repository: lightspeed-core/lightspeed-stack

Length of output: 244


🏁 Script executed:

#!/bin/bash
# Look at the actual infer endpoint source code to understand real error handling
sed -n '1,100p' src/app/endpoints/rlsapi_v1.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 3357


🏁 Script executed:

#!/bin/bash
# Search for where the error messages are defined or generated
rg -n 'Missing required|Invalid.*attachment|attatchment' src/ --type py

Repository: lightspeed-core/lightspeed-stack

Length of output: 848


🏁 Script executed:

#!/bin/bash
# Check RlsapiV1Context to understand attachment/mimetype handling
rg -n 'RlsapiV1Context|attachment|mimetype' src/models/rlsapi/requests.py -A 5 -B 2

Repository: lightspeed-core/lightspeed-stack

Length of output: 2975


Fix 422 response examples in /v1/infer—they're copy-pasted from /v1/query and reference wrong fields.

The 422 examples incorrectly reference ['query', 'model', 'provider'] (from /v1/query endpoint), but RlsapiV1InferRequest only requires question. The error message examples will mislead clients and code generators that rely on the OpenAPI spec.

Additionally, fix the typo: "attatchment" → "attachment", and update the message to reflect the actual validation behavior for /v1/infer context (which validates mimetype, not generic "attachment type").

Proposed fix
                     "422": {
                         "description": "Request validation failed",
                         "content": {
                             "application/json": {
                                 "schema": {
                                     "$ref": "#/components/schemas/UnprocessableEntityResponse"
                                 },
                                 "examples": {
                                     "invalid format": {
                                         "value": {
                                             "detail": {
                                                 "cause": "Invalid request format. The request body could not be parsed.",
                                                 "response": "Invalid request format"
                                             }
                                         }
                                     },
                                     "missing attributes": {
                                         "value": {
                                             "detail": {
-                                                "cause": "Missing required attributes: ['query', 'model', 'provider']",
+                                                "cause": "Missing required attributes: ['question']",
                                                 "response": "Missing required attributes"
                                             }
                                         }
                                     },
                                     "invalid value": {
                                         "value": {
                                             "detail": {
-                                                "cause": "Invalid attatchment type: must be one of ['text/plain', 'application/json', 'application/yaml', 'application/xml']",
+                                                "cause": "Invalid attachment mimetype",
                                                 "response": "Invalid attribute value"
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     },
🤖 Prompt for AI Agents
In @docs/openapi.json around lines 3554 - 3695, Update the 422 response examples
for the /v1/infer operation to reflect RlsapiV1InferRequest: change the "missing
attributes" example to reference only ['question'], fix the typo "attatchment" →
"attachment" in the "invalid value" example, and update that message to state
validation is against attachment mimetype (e.g., "Invalid attachment mimetype:
must be one of [...]") instead of the generic "attachment type" so examples
accurately mirror the infer endpoint's validation behavior.

Comment on lines +4025 to +4053
"text/plain": {
"schema": {
"$ref": "#/components/schemas/InternalServerErrorResponse"
}
}
}
},
"503": {
"description": "Service unavailable",
"content": {
"application/json": {
"examples": {
"llama stack": {
"value": {
"detail": {
"cause": "Connection error while trying to reach backend service.",
"response": "Unable to connect to Llama Stack"
}
}
}
}
},
"text/plain": {
"schema": {
"$ref": "#/components/schemas/ServiceUnavailableResponse"
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find metrics endpoint implementation and error handling
rg -n "metrics" . --type py --type json -i -C 3 | head -100

Repository: lightspeed-core/lightspeed-stack

Length of output: 6293


🏁 Script executed:

#!/bin/bash
# Search for /metrics endpoint in FastAPI/routes
fd . --type f -name "*.py" | xargs rg -l "metrics" | grep -E "(route|endpoint|app)" | head -20

Repository: lightspeed-core/lightspeed-stack

Length of output: 847


🏁 Script executed:

#!/bin/bash
# Look for the OpenAPI file and verify its structure
cat docs/openapi.json | jq '.paths."/metrics"' | head -200

Repository: lightspeed-core/lightspeed-stack

Length of output: 3599


🏁 Script executed:

#!/bin/bash
# Examine the metrics endpoint implementation
cat src/app/endpoints/metrics.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 2102


🏁 Script executed:

#!/bin/bash
# Check the schema definitions for these error responses
rg -A 10 "UnauthorizedResponse|ForbiddenResponse|InternalServerErrorResponse|ServiceUnavailableResponse" docs/openapi.json | head -150

Repository: lightspeed-core/lightspeed-stack

Length of output: 7931


🏁 Script executed:

#!/bin/bash
# Look for exception handlers or error handling in the main app
rg -n "HTTPException|Exception|status_code" src/app/main.py -C 3 | head -100

Repository: lightspeed-core/lightspeed-stack

Length of output: 1200


🏁 Script executed:

#!/bin/bash
# Find the openapi_response method implementation
rg -n "openapi_response" src/ -A 5 | head -100

Repository: lightspeed-core/lightspeed-stack

Length of output: 7660


🏁 Script executed:

#!/bin/bash
# Check the response classes to understand how they generate openapi specs
rg -n "class.*Response" src/models/responses.py -A 10 | head -150

Repository: lightspeed-core/lightspeed-stack

Length of output: 5447


🏁 Script executed:

#!/bin/bash
# Get the error response base class and its openapi_response method implementation
sed -n '1218,1280p' src/models/responses.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 2645


🏁 Script executed:

#!/bin/bash
# Find what class UnauthorizedResponse extends
rg -n "class UnauthorizedResponse" src/models/responses.py -A 20

Repository: lightspeed-core/lightspeed-stack

Length of output: 1025


🏁 Script executed:

#!/bin/bash
# Check AbstractErrorResponse class definition
rg -n "class AbstractErrorResponse" src/models/responses.py -A 30

Repository: lightspeed-core/lightspeed-stack

Length of output: 1224


🏁 Script executed:

#!/bin/bash
# Search for where text/plain might be added to error responses in OpenAPI generation
rg -n "text/plain" src/ --type py -C 3

Repository: lightspeed-core/lightspeed-stack

Length of output: 5891


🏁 Script executed:

#!/bin/bash
# Check if there's custom OpenAPI schema generation or processing
rg -n "openapi" src/app/main.py -i -C 3

Repository: lightspeed-core/lightspeed-stack

Length of output: 313


🏁 Script executed:

#!/bin/bash
# Look for FastAPI app initialization and custom schema/OpenAPI customization
rg -n "app = FastAPI\|get_openapi\|get_schema" src/ -B 2 -A 10 --type py

Repository: lightspeed-core/lightspeed-stack

Length of output: 58


🏁 Script executed:

#!/bin/bash
# Check if there's any schema modification after routes are added
rg -n "components.*schemas\|text/plain" docs/openapi.json -B 2 -A 2 | head -80

Repository: lightspeed-core/lightspeed-stack

Length of output: 58


🏁 Script executed:

#!/bin/bash
# Search for code that modifies OpenAPI spec or adds content types
rg -n "content.*text/plain\|text/plain.*schema" . --type py -C 2

Repository: lightspeed-core/lightspeed-stack

Length of output: 58


🏁 Script executed:

#!/bin/bash
# Check if there's a script or code that generates the openapi.json file
fd -type f -name "*.py" | xargs rg -l "openapi.json\|to_schema\|get_openapi" | head -10

Repository: lightspeed-core/lightspeed-stack

Length of output: 246


🏁 Script executed:

#!/bin/bash
# Look at how the openapi.json is generated - check if there's a script
fd -type f \( -name "*openapi*" -o -name "*schema*" \) | grep -E "\.(py|sh)$"

Repository: lightspeed-core/lightspeed-stack

Length of output: 246


🏁 Script executed:

#!/bin/bash
# Search for where text/plain might be added in error response handling
rg -n "text.plain" . --glob="*.py" -C 2

Repository: lightspeed-core/lightspeed-stack

Length of output: 15954


🏁 Script executed:

#!/bin/bash
# Check if openapi.json is manually created or generated
find . -name "*.py" -o -name "*.sh" | xargs grep -l "openapi.json" 2>/dev/null | head -5

Repository: lightspeed-core/lightspeed-stack

Length of output: 153


🏁 Script executed:

#!/bin/bash
# Look for FastAPI exception handlers that might add text/plain
rg -n "exception_handler\|@app.exception" src/app/main.py -A 15

Repository: lightspeed-core/lightspeed-stack

Length of output: 58


🏁 Script executed:

#!/bin/bash
# Examine the generate_openapi_schema.py script
cat ./scripts/generate_openapi_schema.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 3133


🏁 Script executed:

#!/bin/bash
# Also check the test for OpenAPI JSON
head -100 ./tests/integration/test_openapi_json.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 3358


🏁 Script executed:

#!/bin/bash
# Check how FastAPI's get_openapi processes response_class
rg -n "response_class" src/app/endpoints/metrics.py -B 3 -A 3

Repository: lightspeed-core/lightspeed-stack

Length of output: 262


🏁 Script executed:

#!/bin/bash
# Look at how other endpoints handle error responses with different response_class
rg -n "response_class.*PlainText" src/app/endpoints/ -C 2

Repository: lightspeed-core/lightspeed-stack

Length of output: 364


🏁 Script executed:

#!/bin/bash
# Check if there's any post-processing of the openapi.json in generate_openapi_schema.py
tail -50 ./scripts/generate_openapi_schema.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 1606


🏁 Script executed:

#!/bin/bash
# Let's verify what the actual error response looks like when an error occurs
cat tests/unit/app/endpoints/test_metrics.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 2054


Remove or fix text/plain content-type in /metrics error responses — they incorrectly reference JSON schemas.

The /metrics endpoint declares response_class=PlainTextResponse for successful responses, but error responses (401, 403, 500, 503) in the OpenAPI spec include both application/json (with JSON examples) and text/plain (with JSON schema refs). In reality, all error responses from the exception handler return JSON only; text/plain is never used for errors and should not reference JSON schemas. Either remove text/plain from error responses, or change it to type: string for consistency.

Proposed fix (change `text/plain` errors to plain string type)
                     "500": {
@@
                             "text/plain": {
                                 "schema": {
-                                    "$ref": "#/components/schemas/InternalServerErrorResponse"
+                                    "type": "string"
                                 }
                             }
                         }
                     }
                     "503": {
@@
                             "text/plain": {
                                 "schema": {
-                                    "$ref": "#/components/schemas/ServiceUnavailableResponse"
+                                    "type": "string"
                                 }
                             }
                         }
                     }

(Apply the same change to 401 and 403 responses.)

🤖 Prompt for AI Agents
In @docs/openapi.json around lines 4025 - 4053, The OpenAPI for the /metrics
endpoint incorrectly includes "text/plain" response entries that reference JSON
schemas (e.g., InternalServerErrorResponse, ServiceUnavailableResponse) even
though the exception handler returns JSON; update the 401/403/500/503 responses
to either remove the "text/plain" content type entirely or replace each
"text/plain" schema with a plain string schema (type: string) to reflect actual
plain-text responses for successful /metrics only, ensuring consistency with
response_class=PlainTextResponse and keeping the JSON "application/json" error
examples intact.

Comment on lines +4101 to +4137
"/a2a": {
"get": {
"tags": [
"a2a"
],
"summary": "Handle A2A Jsonrpc",
"description": "Handle A2A JSON-RPC requests following the A2A protocol specification.\n\nThis endpoint uses the DefaultRequestHandler from the A2A SDK to handle\nall JSON-RPC requests including message/send, message/stream, etc.\n\nThe A2A SDK application is created per-request to include authentication\ncontext while still leveraging FastAPI's authorization middleware.\n\nAutomatically detects streaming requests (message/stream JSON-RPC method)\nand returns a StreamingResponse to enable real-time chunk delivery.\n\nArgs:\n request: FastAPI request object\n auth: Authentication tuple\n mcp_headers: MCP headers for context propagation\n\nReturns:\n JSON-RPC response or streaming response",
"operationId": "handle_a2a_jsonrpc_a2a_post",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
},
"post": {
"tags": [
"a2a"
],
"summary": "Handle A2A Jsonrpc",
"description": "Handle A2A JSON-RPC requests following the A2A protocol specification.\n\nThis endpoint uses the DefaultRequestHandler from the A2A SDK to handle\nall JSON-RPC requests including message/send, message/stream, etc.\n\nThe A2A SDK application is created per-request to include authentication\ncontext while still leveraging FastAPI's authorization middleware.\n\nAutomatically detects streaming requests (message/stream JSON-RPC method)\nand returns a StreamingResponse to enable real-time chunk delivery.\n\nArgs:\n request: FastAPI request object\n auth: Authentication tuple\n mcp_headers: MCP headers for context propagation\n\nReturns:\n JSON-RPC response or streaming response",
"operationId": "handle_a2a_jsonrpc_a2a_post",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {}
}
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's check the actual operationIds in the openapi.json for /a2a
rg -A 15 '"/a2a"' docs/openapi.json | grep -E '(operationId|"get"|"post")'

Repository: lightspeed-core/lightspeed-stack

Length of output: 158


🏁 Script executed:

#!/bin/bash
# Let's also search for the actual route definitions in the FastAPI codebase
# to verify if /a2a supports both GET and POST
find . -name "*.py" -type f | head -20 | xargs rg -l "/a2a" 2>/dev/null || rg -r '.py' "/a2a"

Repository: lightspeed-core/lightspeed-stack

Length of output: 102


🏁 Script executed:

#!/bin/bash
# Search for A2A-related route definitions more broadly
rg -n "a2a" --type py -i | grep -E "(route|@|/a2a)" | head -30

Repository: lightspeed-core/lightspeed-stack

Length of output: 2625


🏁 Script executed:

#!/bin/bash
# Inspect the actual route definitions in a2a.py
cat -n src/app/endpoints/a2a.py | head -100

Repository: lightspeed-core/lightspeed-stack

Length of output: 3998


🏁 Script executed:

#!/bin/bash
# Search for @router decorators in the a2a.py file to see which methods are actually defined
rg -n "@router\." src/app/endpoints/a2a.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 325


🏁 Script executed:

#!/bin/bash
# Also check if there's a /a2a/health endpoint mentioned in the openapi.json
rg -B5 -A10 '"/a2a/health"' docs/openapi.json | head -50

Repository: lightspeed-core/lightspeed-stack

Length of output: 645


🏁 Script executed:

#!/bin/bash
# Let's get the complete /a2a endpoint definition to see both operationIds
rg -A 40 '"/a2a": {' docs/openapi.json | head -80

Repository: lightspeed-core/lightspeed-stack

Length of output: 157


🏁 Script executed:

#!/bin/bash
# Verify the exact line where GET operationId is defined
sed -n '4101,4137p' docs/openapi.json | grep -n "operationId"

Repository: lightspeed-core/lightspeed-stack

Length of output: 204


🏁 Script executed:

#!/bin/bash
# Check the POST operationId as well
rg -B5 -A15 '"post": {' docs/openapi.json | grep -A 10 '"/a2a"' | head -20

Repository: lightspeed-core/lightspeed-stack

Length of output: 157


🏁 Script executed:

#!/bin/bash
# Let's view the exact lines to see both operationIds clearly
sed -n '4101,4137p' docs/openapi.json

Repository: lightspeed-core/lightspeed-stack

Length of output: 2683


🏁 Script executed:

#!/bin/bash
# Check if operationId uniqueness is enforced or if duplicates break OpenAPI tooling
# Search for other duplicate operationIds in the same file
rg -n '"operationId"' docs/openapi.json | awk -F: '{print $3}' | sort | uniq -d | head -10

Repository: lightspeed-core/lightspeed-stack

Length of output: 107


🏁 Script executed:

#!/bin/bash
# Verify the FastAPI route definition to confirm both methods are real
sed -n '683p' src/app/endpoints/a2a.py

Repository: lightspeed-core/lightspeed-stack

Length of output: 147


Fix duplicate operationId for /a2a GET and POST methods (breaks codegen/tooling).

Both GET and POST methods use handle_a2a_jsonrpc_a2a_post, causing OpenAPI codegen and tooling to fail. The FastAPI route at line 683 of src/app/endpoints/a2a.py genuinely supports both methods via @router.api_route("/a2a", methods=["GET", "POST"]), so both need distinct operationIds following REST conventions.

Proposed fix
         "/a2a": {
             "get": {
-                "operationId": "handle_a2a_jsonrpc_a2a_post",
+                "operationId": "handle_a2a_jsonrpc_a2a_get",
             "post": {
                 "operationId": "handle_a2a_jsonrpc_a2a_post",
🤖 Prompt for AI Agents
In @docs/openapi.json around lines 4101 - 4137, The OpenAPI has duplicate
operationId "handle_a2a_jsonrpc_a2a_post" for the "/a2a" GET and POST entries
which breaks tooling; fix by assigning unique operationIds (e.g.,
"handle_a2a_jsonrpc_a2a_get" for GET and keep "handle_a2a_jsonrpc_a2a_post" for
POST) either by updating the generated docs/openapi.json fragment or by adding
explicit operation_id values when registering the route (the
@router.api_route("/a2a", methods=["GET","POST"]) registration) so the GET and
POST operations have distinct operationId values.

Comment on lines +8116 to +8148
"RlsapiV1Context": {
"properties": {
"stdin": {
"type": "string",
"title": "Stdin",
"description": "Redirect input from stdin",
"default": "",
"examples": [
"piped input from previous command"
]
},
"attachments": {
"$ref": "#/components/schemas/RlsapiV1Attachment",
"description": "File attachment data"
},
"terminal": {
"$ref": "#/components/schemas/RlsapiV1Terminal",
"description": "Terminal output context"
},
"systeminfo": {
"$ref": "#/components/schemas/RlsapiV1SystemInfo",
"description": "Client system information"
},
"cla": {
"$ref": "#/components/schemas/RlsapiV1CLA",
"description": "Command line assistant metadata"
}
},
"additionalProperties": false,
"type": "object",
"title": "RlsapiV1Context",
"description": "Context data for rlsapi v1 /infer request.\n\nAttributes:\n stdin: Redirect input read by command-line-assistant.\n attachments: Attachment object received by the client.\n terminal: Terminal object received by the client.\n systeminfo: System information object received by the client.\n cla: Command Line Assistant information."
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the specific lines mentioned in the review
sed -n '8116,8148p' docs/openapi.json

Repository: lightspeed-core/lightspeed-stack

Length of output: 208


🏁 Script executed:

# Also check the second location mentioned
sed -n '8241,8286p' docs/openapi.json

Repository: lightspeed-core/lightspeed-stack

Length of output: 2041


🏁 Script executed:

# Search for RlsapiV1SystemInfo definition to verify the description
rg -n 'RlsapiV1SystemInfo' docs/openapi.json -A 15

Repository: lightspeed-core/lightspeed-stack

Length of output: 4143


🏁 Script executed:

# Search for attachments usage in the codebase to understand if it should be array
rg -n '"attachments"' docs/openapi.json -B 2 -A 2

Repository: lightspeed-core/lightspeed-stack

Length of output: 711


🏁 Script executed:

# Check the full attachments definition around line 7322
sed -n '7320,7345p' docs/openapi.json

Repository: lightspeed-core/lightspeed-stack

Length of output: 1258


🏁 Script executed:

# Also check the RlsapiV1Attachment schema definition
rg -n '"RlsapiV1Attachment"' docs/openapi.json -A 20 | head -40

Repository: lightspeed-core/lightspeed-stack

Length of output: 2019


🏁 Script executed:

# Search for RlsapiV1Context examples and usage
rg -n 'RlsapiV1Context' docs/openapi.json -B 2 -A 2 | head -60

Repository: lightspeed-core/lightspeed-stack

Length of output: 2029


🏁 Script executed:

# Check if there are any other references to this in the codebase
rg -n 'attachments' docs/openapi.json | grep -i rlsapi

Repository: lightspeed-core/lightspeed-stack

Length of output: 1093


Fix RlsapiV1SystemInfo description field reference and RlsapiV1Context attachments naming inconsistency.

RlsapiV1SystemInfo description incorrectly references system_id when the actual field is id. Additionally, the attachments field is plural but the schema references a single RlsapiV1Attachment object; either rename attachmentsattachment to match the schema, or change the schema to support an array of attachments.

Proposed fix
             "RlsapiV1Context": {
                 "properties": {
@@
-                    "attachments": {
+                    "attachment": {
                         "$ref": "#/components/schemas/RlsapiV1Attachment",
                         "description": "File attachment data"
                     },
@@
             "RlsapiV1SystemInfo": {
@@
-                "description": "System information from rlsapi v1 context.\n\nAttributes:\n    os: The operating system of the client machine.\n    version: The version of the operating system.\n    arch: The architecture of the client machine.\n    system_id: The id of the client machine."
+                "description": "System information from rlsapi v1 context.\n\nAttributes:\n    os: The operating system of the client machine.\n    version: The version of the operating system.\n    arch: The architecture of the client machine.\n    id: The id of the client machine."
             },

Also applies to: 8241-8286

🤖 Prompt for AI Agents
In @docs/openapi.json around lines 8116 - 8148, Update the RlsapiV1SystemInfo
schema description to reference the actual field name "id" instead of
"system_id", and fix the RlsapiV1Context attachments inconsistency by either
renaming the property "attachments" to "attachment" to match the single
RlsapiV1Attachment schema or by changing the "attachments" property to be an
array (type: "array", items: { "$ref": "#/components/schemas/RlsapiV1Attachment"
}) and updating its description accordingly; apply the same change wherever
RlsapiV1Context and RlsapiV1SystemInfo appear (also at the later block around
the other occurrence).

"detail": {
"cause": "Missing required attributes: ['query', 'model', 'provider']",
"response": "Missing required attributes"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in error message: "attatchment" → "attachment"

The word "attatchment" is misspelled in the error message example. This typo also appears in other endpoint examples (lines 1192, 1505).

📝 Proposed fix
-    "cause": "Invalid attatchment type: must be one of ['text/plain', 'application/json', 'application/yaml', 'application/xml']",
+    "cause": "Invalid attachment type: must be one of ['text/plain', 'application/json', 'application/yaml', 'application/xml']",

Apply the same fix to lines 1192 and 1505.

Also applies to: 3203-3203

🤖 Prompt for AI Agents
In @docs/openapi.md at line 3192, Replace the misspelled token "attatchment"
with the correct spelling "attachment" wherever it appears in the OpenAPI error
message examples (i.e., update the literal string "attatchment" to "attachment"
across all occurrences in the document). Ensure you update every example
response/example text that contains the exact token "attatchment" so the error
messages consistently read "attachment".

@tisnik tisnik merged commit 420784e into lightspeed-core:main Jan 12, 2026
19 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant