Conversation
- Reorganize API Reference section with two subgroups: - Python SDK: existing SDK module documentation - Agent Server: new REST API documentation via OpenAPI spec - Generate openapi/agent-server.json from software-agent-sdk FastAPI app - Update generate-api-docs.py to auto-generate OpenAPI spec during doc builds - Remove duplicate API Reference from Remote Agent Server guides section - Update scripts README and shell script to reflect new OpenAPI generation Co-authored-by: openhands <openhands@all-hands.dev>
Regenerated OpenAPI spec with fix from software-agent-sdk that adds the 'Server Details' tag to the root '/' endpoint, preventing it from appearing under a confusing 'API Reference' category. Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
Taste Rating: 🟡 Acceptable → 🔴 Needs rework
The reorganization itself is solid - separating Python SDK from REST API docs makes sense. However, you've created a critical infrastructure failure that will break automated syncing.
[CRITICAL ISSUES]
🔴 Broken Sync Workflow - You renamed openapi/agent-sdk.json → openapi/agent-server.json but forgot to update .github/workflows/sync-agent-sdk-openapi.yml. The workflow still writes to the old filename (line 61: SCHEMA_PATH: openapi/agent-sdk.json and line 91: add-paths: openapi/agent-sdk.json). This will cause silent failures when the nightly sync runs.
🔴 Undocumented Spec Version - The OpenAPI spec in this PR contains security annotations that don't exist when generated from the current main branch of software-agent-sdk:
- PR spec:
"security": [{"APIKeyHeader": []}]on most endpoints - Fresh generation from main:
"security": null
This indicates the spec was either:
- Generated from a different branch/commit of agent-sdk
- Manually modified (which defeats the purpose of automation)
Required Actions:
- Update
.github/workflows/sync-agent-sdk-openapi.ymlto useagent-server.json - Document in the PR description which agent-sdk commit this spec was generated from
- If this aligns with an upstream agent-sdk PR, link to it
[IMPROVEMENT OPPORTUNITIES]
🟢 Good taste: Navigation restructuring is clean and eliminates the duplicate API Reference entry. No notes here.
🟢 Good taste: The rename from "agent-sdk.json" to "agent-server.json" is more accurate since it documents the server API, not the SDK.
VERDICT: ❌ Needs rework - The navigation changes are fine, but the infrastructure issues are blocking.
KEY INSIGHT: This is why CI/CD tests matter. You've renamed a generated file but not the generator - exactly the kind of thing that should be caught by a test that validates the workflow can still run successfully.
Keep the existing pipeline for updating the agent-server OpenAPI spec. The docs.json restructure and openapi/agent-server.json are retained. Co-authored-by: openhands <openhands@all-hands.dev>
| @@ -104,6 +104,11 @@ | |||
| "summary": "Search Conversation Events", | |||
| "description": "Search / List local events", | |||
| "operationId": "search_conversation_events_api_conversations__conversation_id__events_search_get", | |||
| "security": [ | |||
| { | |||
| "APIKeyHeader": [] | |||
There was a problem hiding this comment.
@OpenHands Clone yourself agent-sdk from the same org and look up where does this come from exactly. I think we haven't done anything new like adding another API key header, so why is this newly generated in the generated openapi doc?
There was a problem hiding this comment.
I'm on it! enyst can track my progress at all-hands.dev
There was a problem hiding this comment.
I cloned OpenHands/software-agent-sdk and traced this to the existing optional session-auth dependency, not anything introduced in this PR.
openhands-agent-server/openhands/agent_server/dependencies.py:11defines_SESSION_API_KEY_HEADER = APIKeyHeader(name="X-Session-API-Key", auto_error=False).openhands-agent-server/openhands/agent_server/api.py:198-202attaches that dependency to the whole/apirouter whenconfig.session_api_keysis non-empty.openhands-agent-server/openhands/agent_server/openapi.pygenerates the schema fromapi = create_app(), so it reads the default config from env at import time.
I also verified it locally: with Config(session_api_keys=[]), FastAPI emits no securitySchemes; with Config(session_api_keys=["test-key"]), it emits exactly this APIKeyHeader plus the per-route security block.
So this is not a new header added by the PR — it's the existing X-Session-API-Key auth showing up because the schema was generated in an environment where SESSION_API_KEY / OH_SESSION_API_KEYS_0 was set. If we want the neutral schema in docs, the generator needs to run with those vars unset.
This comment was marked as duplicate.
This comment was marked as duplicate.
Sorry, something went wrong.
There was a problem hiding this comment.
You’re right to push on that wording — the more precise statement is:
openapi.pyitself does not read env insidegenerate_openapi_schema().- The env-sensitive part happens earlier, as an import side effect.
Exact chain:
openhands-agent-server/openhands/agent_server/openapi.pydoesfrom openhands.agent_server.api import apiopenhands-agent-server/openhands/agent_server/api.pydefinesapi = create_app()at module scopecreate_app()callsget_default_config()when no config is passedget_default_config()callsfrom_env(Config, "OH")once and memoizes it in_default_config_add_api_routes()adds the session-auth dependency only ifconfig.session_api_keysis non-empty
So the schema is really determined by whatever env existed when openhands.agent_server.api was first imported in that process.
I verified that behavior explicitly:
- import with no
SESSION_API_KEY, then set it afterwards -> noAPIKeyHeaderappears - import with
SESSION_API_KEYset, then unset it afterwards ->APIKeyHeaderstill appears
That means import order / process env snapshot determines the generated OpenAPI, not the later call to generate_openapi_schema().
So yes: I do think this pattern is error-prone for tooling/scripts/tests/docs generation. In the normal server process it is somewhat less surprising because config is expected to be fixed before startup, but for schema generation it’s pretty brittle because of the combination of:
- module-level singleton app (
api = create_app()) - implicit fallback to env-backed default config
- memoized
_default_config
So I think your instinct was right: the earlier explanation was directionally right about env-sensitivity, but imprecise about where it happens. The real source is import-time app construction + cached default config, not generate_openapi_schema() itself doing a fresh env read.
Co-authored-by: openhands <openhands@all-hands.dev>
There was a problem hiding this comment.
OpenHands-GPT-5.4 here — after digging further, I think the right way to frame this is:
The product contract is that Agent Server has a stable set of REST endpoints / payloads, and it supports optional session-key authentication via X-Session-API-Key when the server is configured with session_api_keys.
What happened here is that the generated OpenAPI appears to be reflecting a deployment snapshot (the env/config present when the app singleton was imported), rather than a canonical product definition.
I think those are importantly different:
- Product contract: paths, schemas, supported auth mechanisms
- Deployment policy: whether this specific server instance has session auth enabled
In other words, the correct product definition is not:
this schema requires
X-Session-API-Keybecause that env happened to be set during generation
It is:
Agent Server supports optional session-header auth (
X-Session-API-Key), enabled by configuration
So I do think there is a design smell on the agent-server side for tooling/codegen:
- module-level
api = create_app() - implicit fallback to env-backed config
- memoized
_default_config
That combination makes schema generation non-deterministic for docs/tests/scripts.
My preference for published docs would be to generate a deterministic canonical schema (probably with session_api_keys=[]) and document separately that X-Session-API-Key is required only when session auth is enabled in the deployment.
Summary of changes
This PR reorganizes the API Reference section and adds REST API documentation for the Agent Server.
Changes
1. Reorganized API Reference Structure
The API Reference section now has two subgroups:
openhands.sdk.agent,openhands.sdk.conversation, etc.)2. Added OpenAPI Spec (
openapi/agent-server.json)software-agent-sdk3. Updated
scripts/generate-api-docs.pyAdded a new step
generate_agent_server_openapi()that:openapi.pyscript from the agent-server packageopenapi/agent-server.json4. Updated Documentation
scripts/README.mdto document the new OpenAPI generationscripts/generate-api-docs.shoutput messages5. Cleanup
agent-sdk.json→agent-server.jsonfor clarityNew Navigation Structure