dbeaver / dbeaver/dbeaver

OpenAI Responses API streaming: SSE parser requires a space after `data:`/`event:`, silently dropping events from spec-compliant servers

Open Beginner friendly
#42,096 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
51.8k
Forks
4.4k
Avg merge
3d 8h
Merged PRs (30d)
188

Description

### Background

When using the built-in AI Chat (CE 26.2) with an OpenAI-compatible provider that implements the Responses API (e.g. Alibaba Cloud DashScope `https://dashscope.aliyuncs.com/compatible-mode/v1/`), prompts are sent and the HTTP request succeeds (200, SSE stream flowing), but no response is ever rendered and the token counter stays at 0. No error is shown.

### Root cause

In `org.jkiss.dbeaver.model.ai.engine.openai.OpenAiAPIStreamConsumer`:

```java
public static final String DATA_EVENT = "data: "; // note the trailing space
private static final String EVENT_EVENT = "event: "; // note the trailing space
...
if (event.startsWith(DATA_EVENT)) { ... } else if (event.startsWith(EVENT_EVENT)) { ... } else { log.debug("Unknown OpenAI event: " + event); }
```

The parser only recognizes lines that start with `"data: "` / `"event: "` (colon **plus** a space).

Per the WHATWG SSE spec (https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation), after parsing the field name, "If the field value starts with a single U+0020 SPACE character, remove it from value." — the space is **optional**. `data:{json}` is perfectly valid SSE and is emitted by several major OpenAI-compatible providers (DashScope among them, verified byte-for-byte with `curl | od -c`).

Because such lines match neither prefix, every chunk falls into the `else` branch (logged only at debug level) and is silently discarded. From the user's perspective the chat just hangs with 0 tokens, which looks like a connectivity problem rather than a parsing one.

### Suggested fix

Parse SSE lines per spec instead of prefix-matching with a hardcoded space, e.g.:

```java
if (event.startsWith("data:")) {
String data = event.substring(5).stripLeading();
...
} else if (event.startsWith("event:")) {
String eventType = event.substring(6).stripLeading();
...
}
```

### Related (same streaming path, minor)

1. `AIHttpUtils.resolve(baseUrl, "models")` uses `URI.resolve`, so a Base URL without a trailing slash (`.../compatible-mode/v1`) resolves to `.../compatible-mode/models` (404). Normalizing the base URL (appending `/` when the path ends with a version segment, or documenting the requirement) would save a lot of debugging. The default OpenAI endpoint happens to end with `/v1/`, which hides this.
2. The legacy-chat fallback in `OpenAIClientResponses.mapHttpError` triggers only when the 400 body contains specific hardcoded strings (`"is not supported via Responses API"`, `"model_not_supported"`, ...). Providers that reject the Responses API with a different error wording (DashScope returns `<400> InternalError.Algo.InvalidParameter ...` for `function_call_output` input items) get no fallback and just error out. A configurable "use Chat Completions API instead of Responses API" switch would make the OpenAI engine work with any compatible provider.

### Environment

- DBeaver 26.2.0.202608301738 CE, macOS aarch64
- Provider: Alibaba Cloud DashScope (OpenAI-compatible mode), model qwen-plus
- Reproduced with plain curl: the SSE stream contains `data:{...}` (no space) while `OpenAiAPIStreamConsumer` requires `data: ` (with space)

Thanks!

Contributor guide

Open the contributing guide

Research direction

Start in org.jkiss.dbeaver.model.ai.engine.openai.OpenAiAPIStreamConsumer and inspect how SSE lines are classified by DATA_EVENT and EVENT_EVENT. Verify handling against the WHATWG SSE field-value rule, including data:{json} without a space; done means compliant streaming events are recognized instead of silently dropped.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
ai, backend-api-design
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.