Repository navigation
feat(agent-server): add standalone prompt enhancement API - #5446
KevinAndrewDong wants to merge 13 commits into
Conversation
Co-authored-by: openhands <openhands@all-hands.dev>
Use endpoint-generated OpenAPI types, preserve payload privacy with context-only tracing, and cover provider errors, cancellation, and multilingual preservation. Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
⏳ Review waiting on checksThe current head
No action is needed. The scheduled scan retries once every check on the head reports a conclusion. This is an automated check - no AI was used to generate this comment. |
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Review: PR #5446 — feat(agent-server): add standalone prompt enhancement API
Head reviewed: 2a35a405fe8f5aa39b3ac067540b84a9bb2943c1 (matches the requested head; no prior reviews or comments from this account).
Scope
In scope. This is the Agent Server REST operation plus its clients/typescript/ mirror, matching the repository ownership rule (SDK/Agent Server -> OpenAPI -> TypeScript client). The Canvas UI portion stays in OpenHands/OpenHands per issue #5217, which carries ready-for-dev and priority:low.
Verified on the current head
- No side effects / server-side credentials.
_load_profileresolves the saved profile viaget_llm_profile_store().load(..., cipher=config.cipher)andenhance_promptmakes one no-tools call (tools=[],max_tokens=MAX_OUTPUT_TOKENS,store=Falsefor the Responses API)._quiet_llmforceslog_completions=False/num_retries=0on a copy, so the stored profile is untouched; tests assert conversation count, active profile, and active agent profile are unchanged and the profile's ownlog_completionsstaysTrue. - Privacy fail-closed.
_prompt_payload_capture_enabled()blocks enhancement whenDEBUG_LLMis set orshould_enable_observability()is true, and the 422 validation handler now drops rawinputfor/api/prompt-enhancement/paths. Tests cover provider-error text, exception-tracing spans, malformed/duplicate JSON, and oversized/parser payloads not echoing drafts or credentials. - Limits, timeout, cancellation. Input/output length limits are enforced in both Pydantic and the route;
asyncio.timeoutwraps profile load and the provider call; the profile-lock wait runs throughasyncio.to_threadso the endpoint deadline still fires (testtest_profile_lock_wait_respects_endpoint_timeout).asyncio.CancelledErrorpropagates (it is aBaseException, not caught by the broadexcept Exception). - Client + generated contract.
PromptEnhancementClientgates on theprompt_enhancement_v1capability, maps typed error bodies, and threads a callerAbortSignalthrough the probe and the enhance call. The checked-inprompt-enhancement-schema.tsmatches regeneration from the current branch's OpenAPI (verified locally withnpm run check:prompt-enhancement-api).
Verification run
uv run pytest -q tests/agent_server/test_prompt_enhancement_router.py tests/agent_server/test_server_details_router.py tests/agent_server/test_openapi_contract.py tests/agent_server/test_openapi_discriminator.py-> 55 passed.npm run test:agent-server-api-tooling,npm run check:prompt-enhancement-api, and the prompt-enhancement client vitest file (6 tests) -> pass.
Non-blocking observation
On the current head, GitHub Actions has only completed the PR-hygiene checks (Validate PR description, check-pr-artifacts -> success); the code checks (Run tests, TypeScript client CI, REST API breakage checks, etc.) are action_required/awaiting approval and have not exercised this commit. The author's local results and my own focused runs are green, but a maintainer should confirm the full CI set runs on this head before merge.
No material correctness, security, compatibility, or acceptance-criterion defect found in the current head.
✅ APPROVED
Co-authored-by: openhands <openhands@all-hands.dev>
Use the matched route to omit private draft inputs from validation errors, including runtime-prefixed requests. Cover prefixed field validation and malformed or resource-heavy JSON with the existing tests. Co-authored-by: openhands <openhands@all-hands.dev>
Disable prompt-cache fallback on the endpoint-local LLM copy and cover chat and Responses transport counts. Verify authenticated enhancement over a real Agent Server HTTP connection without mutating saved state. Co-authored-by: openhands <openhands@all-hands.dev>
Preserve live-server fixture preload and deferred initialization controls. Co-authored-by: openhands <openhands@all-hands.dev>
Merge current main, retain both server capabilities, enforce the SDK output budget, and reject provider options that bypass enhancement boundaries. Add transport regressions and real-server verification recipes. Co-authored-by: openhands <openhands@all-hands.dev>
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Review: PR #5446 — feat(agent-server): add standalone prompt enhancement API
Head reviewed: b5c79948ed830cdb0598a57925ee01f1307e0ca7. No prior review exists on this head (the earlier approval was on the previous head 2a35a405fe8f), so this is a fresh pass.
Scope
In scope. The change is the Agent Server REST operation plus its clients/typescript/ mirror, matching the repository ownership rule (SDK/Agent Server → OpenAPI → typed client). The Canvas UI portion stays in OpenHands/OpenHands per issue #5217, which still carries ready-for-dev and priority:low.
What the current head does
- Server-side credentials, no side effects.
_load_profileresolves the saved profile throughget_llm_profile_store().load(..., cipher=config.cipher);enhance_promptthen makes one no-tools call (tools=[],store=Falseon the Responses path)._quiet_llmcopies the LLM and forceslog_completions=False,num_retries=0,caching_prompt=False, and a boundedmax_output_tokens, leaving the stored profile and normal SDK behavior untouched — the live-HTTP and unit tests assert conversation count, profile list, the saved profile, and itslog_completionsare unchanged. - Bounded generation. The token budget is now set on the LLM copy (
min(effective_max_output_tokens or MAX_OUTPUT_TOKENS, MAX_OUTPUT_TOKENS)) rather than passed as a per-call kwarg, and the code rejects subscription profiles and any non-emptylitellm_extra_body(which providers merge after normal parameters and could restore tools/storage or raise the budget) with a stableunsupported_configurationerror. Tests cover chat/Responses and Azure budget-key mapping across profile budgets. - Privacy fail-closed. Enhancement is refused while
DEBUG_LLMis set orshould_enable_observability()is true, and the 422 handler omits rawinputfor/api/prompt-enhancement/routes using the matched route path (root_path-aware). Tests cover provider-error text, exception-tracing spans, malformed/duplicate/oversized JSON, and a live authenticated server. - Limits, timeout, cancellation. Input/output length limits are enforced in the route;
asyncio.timeoutwraps profile load and the provider call; the profile-lock wait runs viaasyncio.to_threadso the deadline still fires;CancelledErrorpropagates. The generated TypeScript contract matches the current-branch OpenAPI.
Verification performed
uv run pytest -q tests/agent_server/test_prompt_enhancement_router.py tests/agent_server/test_server_details_router.py tests/agent_server/test_openapi_contract.py tests/agent_server/test_openapi_discriminator.py→ 89 passed.npm run test:agent-server-api-tooling,npm run check:prompt-enhancement-api, and the prompt-enhancement client vitest file (6 tests) → pass.
Note for the maintainer: in my sandbox LMNR_PROJECT_API_KEY was set, which globally enables observability and (correctly) makes these routes return unsupported_configuration. With that ambient variable unset — the normal case for the author's local runs and for environments without tracing — all 89 tests pass. This is a fail-closed behavior, not a defect.
Non-blocking observation
On this head, GitHub Actions has only completed the PR-hygiene checks (Validate PR description, check-pr-artifacts → success); the code checks (Run tests, TypeScript client CI, REST API breakage checks, etc.) have not run and are awaiting repository approval. The author's local results and my focused runs are green, but a maintainer should confirm the full CI set runs on this head before merge.
No material correctness, security, compatibility, or acceptance-criterion defect found in the current head.
✅ APPROVED
Resolve the feature-map count as 941, preserving main's 936 sub-features and the five prompt-enhancement additions. Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
|
📁 PR Artifacts Notice This PR contains a |
all-hands-bot
left a comment
There was a problem hiding this comment.
This review was posted by an AI agent (OpenHands).
Reviewed head 592fd232468675449c7c221078f35ce690e47529 (re-fetched current state: PR open, non-draft, head unchanged, no existing review on this head, no unresolved threads).
Scope: Belongs in this repository. It adds an Agent Server REST route plus /server_info capability and mirrors it in clients/typescript, following the repo's Agent Server → OpenAPI → TypeScript client flow to deliver #5217 (currently labeled ready-for-dev). The change is additive: existing /api/profiles, /api/agent-profiles, and /server_info response shapes keep their behavior, and _sanitize_validation_errors preserves its previous output for every non-prompt-enhancement route.
Verification on this head:
uv run pytest tests/agent_server/test_prompt_enhancement_router.py tests/agent_server/test_server_details_router.py tests/agent_server/test_openapi_contract.py tests/agent_server/test_openapi_discriminator.py— 91 passed in the workspace.tests/cross/test_remote_conversation_live_server.py::test_prompt_enhancement_over_authenticated_live_http— passed (auth enforced, capability advertised, saved profile unchanged, no conversation side effects).- Traced the design against base behavior: system-before-user message invariant holds; the chat path passes no tools (
toolsresolves toNonefor an empty list) and the Responses path passesstore=Falsewith no tools; profile credentials flow through the existing profile store and cipher withlog_completions=False,num_retries=0, prompt caching off, and an 8,192-token output cap on the one-off copy only; payload-capturing tracing (DEBUG_LLM and observability, including context-only OTel) fails closed with a typed error; the 45sasyncio.timeoutremains effective because profile-store lock waits run inasyncio.to_thread; error codes cover every class required by #5217, and the transport-level tests assert exactly one provider call per request. - No new third-party npm or PyPI versions were introduced; the new workflow step pins
astral-sh/setup-uvto a full SHA.
CI note: agent-server-stress-tests is the only failing check on this head, failing in test_concurrent_conversations_isolated_and_fast, a wall-clock parallelism budget assertion. The PR's diff touches none of the measured path (no conversation-run, lock, or stress-suite changes), and the identical assertion failure reproduces on pristine origin/main in the same environment (4/4 runs on each head, ~0.8s concurrent wall vs a ~0.63s budget), so this is an unrelated, environment-sensitive flaky budget rather than a regression from this PR. Recent main runs pass the same check, so the budget appears marginal under runner variance.
No material correctness, security, compatibility, or acceptance findings on this diff.
✅ APPROVED
Co-authored-by: openhands <openhands@all-hands.dev>
ffcd00f to
592fd23
Compare
HUMAN:
I shaped the scope and provided review feedback.
AGENT:
AI assistance
Tool(s) used: Codex
How you used it: Assisted with the API/SDK implementation, regression tests, and independent AI review.
Why
This adds the server-side prompt enhancement operation and typed TypeScript access requested in #5217, so clients can improve a draft before starting a conversation while credentials remain server-side.
Summary
Issue Number
Fixes #5217
How to Test
uv run pytest -q tests/agent_server/test_prompt_enhancement_router.py tests/agent_server/test_server_details_router.py tests/agent_server/test_openapi_contract.py tests/agent_server/test_openapi_discriminator.py— 69 passed on Python 3.12, 3.13, and 3.14. The new transport-level regression covers chat and Responses success/cache-error paths; each invokes the provider stub once.uv run pytest -q tests/cross/test_remote_conversation_live_server.py::test_prompt_enhancement_over_authenticated_live_http— passed against real Uvicorn on the final Python 3.13 snapshot, including authentication, capabilities, saved profiles, and unchanged conversation/profile state.cd clients/typescript && npm run test:coverage— 360 passed on Node 22; the same 360 tests passed on Node 24. The compiled client also passed availability and enhancement against the real Python HTTP server on both versions.clients/typescript:npm run test:agent-server-api-tooling,npm run check:prompt-enhancement-api,npm run check:agent-server-api,npm run build,npm run lint, andnpm run format:checkpassed. Lint reported 7 existing warnings.Video/Screenshots
Not applicable; this adds an API and SDK method without a UI change.
Type
Notes
Prompt enhancement is unavailable while LLM tracing or payload logging is enabled, including context-only OpenTelemetry instrumentation: provider exception spans can contain private draft text. Profile-store lock waits run off the event loop so the endpoint deadline remains effective. A caller-owned AbortSignal also cancels the initial capability probe.