Files
ragflow/api
Rene Arredondo 09dc4c8841 fix(agent): return session_id when chat completion produces no events (#15169) (#15228)
## Summary

Fixes #15169 — `POST /api/v1/agents/chat/completions` returned
`data: {}` with no `session_id` when the agent produced no events
(e.g. the reporter's payload sent `"query": ""`).

## Root cause

For `{"agent_id": "...", "query": "", "stream": false}`:

1. No `session_id` in the request → new-session branch at
   `agent_api.py:1278`.
2. `session_id = get_uuid()` at `agent_api.py:1294`.
3. Falls into `_run_workflow_session`.
4. `canvas.run(query="")` produces no events, so `final_ans`
   stays `{}`.
5. Non-streaming path then hit:

   ```python
   if not final_ans:
       await commit_runtime_replica()
       return get_result(data={})
   ```

   `session_id` was allocated but silently dropped on the way out.

The streaming path had the same shape (only a bare `[DONE]` was
yielded — no SSE event carrying `session_id`). The
session-continuation path at `agent_api.py:1463` had the same bug
for callers that passed `session_id` and got `{}` back.

The successful (non-empty) paths were fine because every canvas
event has `ans["session_id"] = session_id` attached before being
yielded / captured into `final_ans` (see
`agent_api.py:255` and `:303`).

## Fix

Three minimal changes, all in
`api/apps/restful_apis/agent_api.py`:

1. **`_run_workflow_session` (non-streaming)**:
   `return get_result(data={"session_id": session_id})` instead of
   `data={}`.
2. **`_run_workflow_session` (SSE)**: if the canvas loop emits no
   events, yield one
   `data:{"session_id": "...", "data": {}}` event before
   `[DONE]`, so the client receives the id over the wire.
3. **`agent_chat_completion` session-continuation**: echo the
   caller-supplied `session_id` back in the empty-events case
   instead of `{}`.

No change needed on the happy paths — they already attach
`session_id` to every event.

## Test plan

- [ ] Repro from the issue: `POST /api/v1/agents/chat/completions`
      with `{"agent_id": "<id>", "query": "", "stream": false}`.
      Response `data` should now contain `session_id`.
- [ ] Same payload with `"stream": true`. SSE stream should
      contain one event with `session_id` before `data:[DONE]`.
- [ ] Same shape but with a real, non-empty `"query"` (new
      session). Response should be unchanged from before — every
      event still carries `session_id`, final response still
      includes it on `final_ans`.
- [ ] Pass an existing `session_id` plus `"query": ""`. Response
      should echo that `session_id` back instead of `{}`.
- [ ] Pass an existing `session_id` plus a normal query. Response
      should be unchanged from before.
- [ ] `openai-compatible: true` path is untouched — sanity-check
      it still works.
- [ ] Run `uv run pytest` to make sure no existing tests regress.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
- [ ] New Feature (non-breaking change which adds functionality)
- [ ] Documentation Update
- [ ] Refactoring
- [ ] Performance Improvement
- [ ] Other (please describe):
2026-06-30 16:41:44 +08:00
..
2025-10-18 16:09:48 +08:00