# https://github.com/AnotiaWang/deep-research-web-ui Project Manual

Generated at: 2026-06-26 07:19:32 UTC

## Table of Contents

- [Project Overview & Deployment Modes](#page-1)
- [AI & Web Search Provider Configuration](#page-2)
- [Research Engine, API Endpoints & Data Flow](#page-3)
- [Frontend Components, Search Visualization & History](#page-4)

<a id='page-1'></a>

## Project Overview & Deployment Modes

### Related Pages

Related topics: [AI & Web Search Provider Configuration](#page-2)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)
- [README_zh.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README_zh.md)
- [edgeone.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/edgeone.json)
- [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts)
- [server/api/feedback.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/feedback.post.ts)
- [server/api/report.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/report.post.ts)
- [lib/core/index.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/index.ts)
</details>

# Project Overview & Deployment Modes

## Purpose and Scope

Deep Research Web UI is a browser-based visualization layer for the open-source [`deep-research`](https://github.com/dzhng/deep-research) agent. It wraps a recursive web-research loop — where an LLM generates follow-up questions, performs iterative web searches, and distills learnings — in a four-step user interface: research topic, model feedback, web browsing, and final report. Source: [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md).

The project distinguishes itself from the upstream CLI by emphasizing realtime feedback, search-flow visualization, and a flexible deployment model. Realtime feedback is achieved by streaming AI responses and reflecting them in the UI; search flow is rendered as a tree structure so users can inspect individual nodes (research goal, visited URLs, learnings) and retry failed ones. Source: [i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json).

The core research engine itself is split into a small set of TypeScript modules re-exported through a single entry point. Source: [lib/core/index.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/index.ts).

```text
lib/core/
├── index.ts          // barrel re-export
├── deep-research.ts  // iterative search + final report
└── feedback.ts       // clarification question generator
```

## Supported Providers

The application is intentionally provider-agnostic on both the LLM and the web-search axes. On the AI side, the README advertises OpenAI-compatible endpoints, SiliconFlow, InfiniAI, DeepSeek, OpenRouter, Ollama, and 302.AI. On the web-search side, it lists Tavily (1000 free credits/month), Firecrawl (cloud or self-hosted), fastCRW, and Google PSE. Source: [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md).

Compatibility is preserved by using plain prompt-based JSON extraction rather than newer features such as Structured Outputs. The project ships its own streaming JSON parser that tolerates partial / repaired parses so that weaker models do not break the pipeline. Source: [shared/utils/json.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/utils/json.ts).

The provider catalog has grown steadily through community-driven releases: Google PSE landed in v1.1.9, InfiniAI in v1.1.8, and 302.AI in v1.2.0. Source: [release notes v1.1.9 / v1.1.8 / v1.2.0](https://github.com/AnotiaWang/deep-research-web-ui/releases).

## Deployment Modes

The project supports two distinct operational modes, switched at build/runtime via the `NUXT_PUBLIC_SERVER_MODE` flag. The choice has major implications for where API keys live and where inference requests are executed.

### Client Mode (BYOK)

In Client Mode, configuration values — provider, API key, API base URL, model, context size, web-search settings — are entered through the settings panel and persisted in the browser. All requests to AI and search providers originate directly from the user's browser. The application is a static Nuxt 3 build that can be hosted on any static platform. Source: [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md).

This mode is appropriate when the operator wants maximum privacy and minimal operational footprint. The trade-off is that each user must paste their own keys on first use, which is what motivated the original feature request in [issue #8](https://github.com/AnotiaWang/deep-research-web-ui/issues/8) for environment-variable configuration.

### Server Mode

Server Mode was introduced in [release v1.2.0](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.2.0). Instead of sending requests directly to upstream providers, the browser forwards the heavy LLM calls to two internal Nuxt server routes:

- `POST /api/feedback` — streams clarification questions. Source: [server/api/feedback.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/feedback.post.ts).
- `POST /api/report` — streams the final research report. Source: [server/api/report.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/report.post.ts).

Both handlers read the operator's secrets from `useRuntimeConfig()` and respond with `text/event-stream` so the frontend can render tokens in real time.

Two TypeScript types in `shared/types/config.ts` formalize the split between operator-only secrets and values safe to expose to the browser:

```ts
export interface ServerRuntimeConfig {
  aiProvider: ConfigAiProvider
  aiModel: string
  aiApiKey: string          // server-only
  aiApiBase?: string
  ...
  webSearchApiKey: string   // server-only
  googlePseId?: string
}

export interface PublicRuntimeConfig {
  serverMode: boolean
  aiProvider: ConfigAiProvider
  aiModel: string
  // no API keys, no apiBase
}
```

Source: [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts).

```mermaid
flowchart LR
  subgraph Client["Client Mode (BYOK)"]
    U1[User Browser] -- "API key in localStorage" --> U1
    U1 -- "direct HTTPS" --> P1[AI Provider]
    U1 -- "direct HTTPS" --> S1[Search Provider]
  end
  subgraph Server["Server Mode"]
    U2[User Browser] -- "no secrets" --> N[Nuxt Server]
    N -- "useRuntimeConfig" --> N
    N -- "stream /api/feedback, /api/report" --> P2[AI Provider]
    N -- "API key from env" --> S2[Search Provider]
  end
```

### Operating-Mode Selection

Server Mode is selected by setting `NUXT_PUBLIC_SERVER_MODE` and the rest of the operator configuration in a `.env` file (copied from `.env.example`), then running the published Docker image with `--env-file`. The static-hosting alternative remains EdgeOne Pages, where the project provides a one-click deploy button and pins Node 20.18.0. Source: [README_zh.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README_zh.md), [edgeone.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/edgeone.json).

```mermaid
flowchart TD
  Start{Where do API keys live?}
  Start -- "User's browser" --> CM[Client Mode]
  Start -- "Server .env" --> SM[Server Mode]
  CM --> CM1["Static host (EdgeOne, Docker nginx)"]
  SM --> SM1["Nuxt server runtime (Docker)"]
  SM1 --> SM2["/api/feedback, /api/report"]
```

## Common Pitfalls and Community Notes

- **CORS errors in Client Mode**: Some AI providers block cross-origin browser requests. The UI surfaces a localized hint: "The current API provider may not allow cross-origin requests. Please try a different service provider or contact the provider for support." Source: [i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json).
- **Azure OpenAI**: Issue [#70](https://github.com/AnotiaWang/deep-research-web-ui/issues/70) reports that the URL builder does not yet support Azure's `api-version` query parameter, so Azure deployments may fail unless used through the OpenAI-compatible provider with a custom base URL.
- **PWA / offline use**: A long-standing request in [issue #43](https://github.com/AnotiaWang/deep-research-web-ui/issues/43) for PWA support remains open; the production build is not currently service-worker-enabled.
- **Tavily quota**: Single-account Tavily keys hit their 1k/month ceiling quickly during deep research. A rotation scheme was proposed in [PR #77](https://github.com/AnotiaWang/deep-research-web-ui/pull/77) and merged, so Server Mode deployments can supply a comma-separated key list.

## See Also

- [Provider & Configuration Reference](configuration.md) — detailed env-var table and per-provider notes.
- [Web Search & Browsing Pipeline](web-search.md) — how the recursive search loop and Firecrawl/Tavily integrations work.
- [Internationalization & History](i18n-and-history.md) — translation workflow and the history feature shipped via [issue #57](https://github.com/AnotiaWang/deep-research-web-ui/issues/57).

---

<a id='page-2'></a>

## AI & Web Search Provider Configuration

### Related Pages

Related topics: [Project Overview & Deployment Modes](#page-1), [Research Engine, API Endpoints & Data Flow](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts)
- [lib/ai/providers.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/ai/providers.ts)
- [app/stores/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/stores/config.ts)
- [app/components/ConfigManager.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/components/ConfigManager.vue)
- [app/composables/useAiProvider.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/composables/useAiProvider.ts)
- [app/composables/useWebSearch.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/composables/useWebSearch.ts)
- [lib/core/deep-research.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/deep-research.ts)
- [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)
- [README_zh.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README_zh.md)
- [i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json)
- [i18n/zh.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/zh.json)
</details>

# AI & Web Search Provider Configuration

## Overview

The deep-research-web-ui project decouples its research pipeline from any single AI or search vendor by exposing a pluggable **provider configuration layer**. Every research run accepts a `ConfigAi` and a `ConfigWebSearch` object, so the same UI can target OpenAI-compatible endpoints, regional Chinese providers, or self-hosted models, and can pair them with Tavily, Firecrawl, fastCRW, or Google PSE for web search. The configuration layer governs four things: (1) which provider to use, (2) authentication material, (3) endpoint and language, and (4) per-provider tuning (context size, search topic, rate limit).

Configuration is delivered to the application through one of two parallel paths — a **Client Mode** form that writes to the browser's `localStorage` (see [app/stores/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/stores/config.ts)) and a **Server Mode** path that reads environment variables at boot via Nuxt's runtime config ([shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts)).

## Configuration Modes

The project ships two mutually exclusive deployment modes, selected at build/run time:

- **Client Mode** — Every visitor enters their own AI and search credentials in the in-app settings dialog. Keys never leave the browser; the in-page `ConfigManager.vue` reads them on each research request. This mode is the only one supported by static exports such as `pnpm generate` or EdgeOne Pages ([README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)).
- **Server Mode** — Added in v1.2.0 ([release notes](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.2.0)) in response to long-standing requests to set credentials via environment variables (see [issue #8](https://github.com/AnotiaWang/deep-research-web-ui/issues/8)). The server reads `NUXT_*` variables into `ServerRuntimeConfig`, exposes the non-secret subset through `PublicRuntimeConfig`, and the UI displays a "Server Mode" banner with `configNotice: "Current configuration is set by the server administrator..."` ([i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json)).

```mermaid
flowchart LR
  A[Operator] -->|env vars| B[Nuxt Server<br/>ServerRuntimeConfig]
  B -->|public subset| C[PublicRuntimeConfig]
  C --> D[Browser UI<br/>Settings Dialog]
  E[End User] -->|types keys| D
  D -->|Client Mode| F[localStorage]
  D -->|Server Mode| C
  F --> G[Research Pipeline]
  C --> G
  G --> H[AI Provider]
  G --> I[Search Provider]
```

## Supported AI Providers

The AI provider field is typed as `ConfigAiProvider` in [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts) and is materialised into a model adapter by `getLanguageModel(aiConfig)` inside [lib/core/deep-research.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/deep-research.ts). The README and i18n files enumerate the supported values:

| Provider value | Notes / Source |
| --- | --- |
| `openai-compatible` | Default. Any OpenAI Chat Completions compatible endpoint, including custom `apiBase`. ([README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)) |
| `siliconflow` | Chinese cloud inference. ([i18n/zh.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/zh.json)) |
| `302-ai` | Added in v1.2.0, includes a free sign-up credit. ([i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json)) |
| `infiniai` | Added in v1.1.8. ([release v1.1.8](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.1.8)) |
| `openrouter` | Added in early 2025. ([README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)) |
| `deepseek` | Supports reasoning models such as DeepSeek R1. ([README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)) |
| `ollama` | Self-hosted local models. ([README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)) |

Per-provider settings live in the `ai` section of the i18n file and include `apiKey`, `apiBase`, `model`, and `contextSize`. The `contextSize` field controls how much of the running prompt is sent back to the model and is enforced in the research pipeline through `trimPrompt(..., aiConfig.contextSize)` ([lib/core/deep-research.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/deep-research.ts)); the v1.1.5 release fixed a bug where this value was silently ignored ([release v1.1.5](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.1.5)).

The project deliberately uses "plain prompts" rather than OpenAI's Structured Outputs feature so that older or regional providers that have not yet shipped the newer API surface continue to work ([README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)). Users on Azure OpenAI should note that base URL construction and `api-version` handling is not currently abstracted — see the open report in [issue #70](https://github.com/AnotiaWang/deep-research-web-ui/issues/70).

## Supported Web Search Providers

The `webSearch` block of the configuration controls the SERP and scraping backend. Four providers are first-class:

- **`tavily`** — Default, ~1000 free credits / month. Supports `advancedSearch` (costs one extra credit) and `searchTopic` (one of `'general' | 'news' | 'finance'`), both of which appear as typed fields on `ServerRuntimeConfig` and `PublicRuntimeConfig` ([shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts)). To address the single-account quota problem raised in [issue #75](https://github.com/AnotiaWang/deep-research-web-ui/issues/75), `NUXT_WEB_SEARCH_API_KEY` accepts a comma-separated list (`key1,key2,key3`) and the server rotates through them.
- **`firecrawl`** — Cloud or self-hosted. Self-hosted deployments are configured through `NUXT_WEB_SEARCH_API_BASE` ([README_zh.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README_zh.md)). Since v1.1.3, scraping is restricted to the `Markdown` format to keep downstream LLM prompts predictable ([release v1.1.3](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.1.3)). Note: [issue #73](https://github.com/AnotiaWang/deep-research-web-ui/issues/73) reports that the in-app `concurrencyLimit` setting is not yet honoured when Firecrawl runs in self-hosted mode.
- **`crw`** — A Firecrawl-compatible binary scraper that can be self-hosted or used as a cloud service. Identical configuration surface to Firecrawl ([i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json)).
- **`google-pse`** — Added in v1.1.9 ([release v1.1.9](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.1.9)). Requires both an API key (`NUXT_WEB_SEARCH_API_KEY`) and a Programmable Search Engine ID exposed as `NUXT_PUBLIC_GOOGLE_PSE_ID`. Multiple keys for rotation are supported the same way as Tavily.

The `concurrencyLimit` field, added in v1.1.1, bounds the number of in-flight search tasks to avoid rate limiting ([release v1.1.1](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.1.1)). `searchLanguage` overrides the language used in the search query while leaving the UI/report language untouched ([i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json)).

## Server Mode Environment Variables

When `NUXT_PUBLIC_SERVER_MODE=true` is set, the server-side runtime config below takes precedence over any client-side settings. Operators normally inject these via the Docker `docker run -e ...` flags shown in the README.

| Variable | Purpose | Default |
| --- | --- | --- |
| `NUXT_AI_API_KEY` | Server-side AI provider key | — |
| `NUXT_PUBLIC_AI_PROVIDER` | AI provider id (see table above) | `openai-compatible` |
| `NUXT_WEB_SEARCH_API_KEY` | Search provider key; supports comma-separated rotation | — |
| `NUXT_WEB_SEARCH_API_BASE` | Custom endpoint (e.g. self-hosted Firecrawl) | — |
| `NUXT_PUBLIC_WEB_SEARCH_PROVIDER` | Search provider id | `tavily` |
| `NUXT_PUBLIC_WEB_SEARCH_CONCURRENCY_LIMIT` | Max concurrent searches | `2` |
| `NUXT_PUBLIC_WEB_SEARCH_SEARCH_LANGUAGE` | BCP-47 language code for queries | `en` |
| `NUXT_PUBLIC_TAVILY_ADVANCED_SEARCH` | Toggle Tavily's higher-quality tier | `false` |
| `NUXT_PUBLIC_TAVILY_SEARCH_TOPIC` | `general` / `news` / `finance` | `general` |
| `NUXT_PUBLIC_GOOGLE_PSE_ID` | Required when provider is `google-pse` | — |

(Sources: [README_zh.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README_zh.md) and the `PublicRuntimeConfig` interface in [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts).)

## Common Failure Modes

- **CORS rejection in Client Mode** — When a provider does not advertise permissive CORS headers, browser calls fail with `requestBlockedByCORS`. The error message in [i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json) advises switching providers or moving to Server Mode.
- **"Invalid JSON structure"** — Older or smaller models occasionally return malformed structured output. The pipeline surfaces a translated `invalidStructuredOutput` error suggesting a larger model ([i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json)). v1.1.2 reduced the frequency of this error ([release v1.1.2](https://github.com/AnotiaWang/deep-research-web-ui/releases/tag/v1.1.2)).
- **Tavily quota exhaustion** — Solved by configuring multiple keys in `NUXT_WEB_SEARCH_API_KEY`, added in response to [issue #75](https://github.com/AnotiaWang/deep-research-web-ui/issues/75).
- **Self-hosted Firecrawl rate limiting** — The client-side `concurrencyLimit` is not propagated to a self-hosted Firecrawl instance; see [issue #73](https://github.com/AnotiaWang/deep-research-web-ui/issues/73).

## See Also

- [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md) — feature list and deployment quickstart
- [Release notes index](https://github.com/AnotiaWang/deep-research-web-ui/releases) — version history (v1.1.1 → v1.2.0) cited above
- [dzhng/deep-research](https://github.com/dzhng/deep-research) — the underlying research engine this UI wraps

---

<a id='page-3'></a>

## Research Engine, API Endpoints & Data Flow

### Related Pages

Related topics: [AI & Web Search Provider Configuration](#page-2), [Frontend Components, Search Visualization & History](#page-4)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- [lib/core/deep-research.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/deep-research.ts)
- [lib/core/feedback.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/feedback.ts)
- [lib/core/index.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/index.ts)
- [lib/prompt.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/prompt.ts)
- [app/utils/prompt.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/utils/prompt.ts)
- [server/api/research.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/research.post.ts)
- [server/api/feedback.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/feedback.post.ts)
- [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts)
- [shared/utils/json.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/utils/json.ts)
- [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md)
- [edgeone.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/edgeone.json)
</details>

# Research Engine, API Endpoints & Data Flow

## 1. Purpose and Scope

The **Research Engine** is the heart of `deep-research-web-ui`. It wraps the original Node-based research loop from [dzhng/deep-research](https://github.com/dzhng/deep-research) into a set of TypeScript modules that can be invoked both **inside the browser** (Client Mode) and **from Nitro server routes** (Server Mode). Source: [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md).

The engine drives a four-stage user journey visible in the UI:

1. **Research Topic** — user submits a query, depth, and breadth.
2. **Model Feedback** — AI asks clarifying follow-up questions.
3. **Web Browsing** — recursive search/scrape loop produces a tree of learnings.
4. **Research Report** — final synthesis streamed back to the UI.

Source: [i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json) (sections `researchTopic`, `modelFeedback`, `webBrowsing`, `researchReport`).

In **Server Mode** (introduced in v1.2.0), the engine is exposed through HTTP endpoints under `server/api/`, allowing external clients to invoke the pipeline programmatically — a direction requested by the community in [issue #79](https://github.com/AnotiaWang/deep-research-web-ui/issues/79).

## 2. Core Library Layout (`lib/core/`)

`lib/core/index.ts` is a thin facade that re-exports the two engine entry points:

```ts
export * from './deep-research'
export * from './feedback'
```

Source: [lib/core/index.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/lib/core/index.ts).

- **`generateFeedback(...)`** in `lib/core/feedback.ts` — builds a clarifying-questions prompt and streams an array of questions back as deltas.
- **`deepResearch(...)`** in `lib/core/deep-research.ts` — orchestrates the iterative breadth/depth loop, producing a tree of search nodes whose leaves accumulate learnings.

Both functions accept an `aiConfig: ConfigAi` parameter so the engine is provider-agnostic. Prompts are factored into `lib/prompt.ts` and `app/utils/prompt.ts`, allowing browser and server bundles to share wording while keeping the server bundle trim.

## 3. Server API Endpoints

Server Mode is implemented with Nitro routes in `server/api/`. Each endpoint accepts a JSON body, attaches the server-side `runtimeConfig`, and responds with a **Server-Sent Events** stream so the UI can render partial results.

### 3.1 `POST /api/feedback`

The feedback endpoint validates `query` and `language`, then delegates to `generateFeedback`:

```ts
const serverConfig: ConfigAi = {
  provider: runtimeConfig.public.aiProvider as ConfigAi['provider'],
  apiKey: runtimeConfig.aiApiKey,
  apiBase: runtimeConfig.aiApiBase,
  model: runtimeConfig.public.aiModel,
  contextSize: runtimeConfig.public.aiContextSize,
}
```

It sets `Content-Type: text/event-stream`, `Cache-Control: no-cache`, and `Connection: keep-alive`, then iterates the async generator, encoding each chunk as `data: <json>\n\n`. Errors are serialized into a final SSE error event rather than thrown. Source: [server/api/feedback.post.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/server/api/feedback.post.ts).

### 3.2 `POST /api/research`

The research endpoint follows the same pattern but invokes the longer-running `deepResearch(...)` generator. Because the loop runs many sequential search/scrape calls, this endpoint benefits from the `webSearchConcurrencyLimit` setting — which the community reports is not always honored by self-hosted Firecrawl, see [issue #73](https://github.com/AnotiaWang/deep-research-web-ui/issues/73).

## 4. Data Flow

The end-to-end flow in Server Mode looks like this:

```mermaid
sequenceDiagram
    participant Browser as Browser UI
    participant Nitro as Nitro API Route
    participant Engine as lib/core (Engine)
    participant AI as AI Provider
    participant Search as Web Search Provider

    Browser->>Nitro: POST /api/feedback (query, language)
    Nitro->>Engine: generateFeedback(aiConfig)
    Engine->>AI: stream chat completion
    AI-->>Engine: deltas (reasoning + text)
    Engine-->>Nitro: {type:'object'|'reasoning'} events
    Nitro-->>Browser: SSE stream

    Browser->>Nitro: POST /api/research (answers, depth, breadth)
    Nitro->>Engine: deepResearch(aiConfig, webSearchConfig)
    loop depth iterations
        Engine->>Search: search(query) × breadth
        Search-->>Engine: URLs + snippets
        Engine->>AI: extract learnings
        Engine-->>Nitro: node + learnings events
    end
    Engine->>AI: synthesize report
    Engine-->>Nitro: final report stream
    Nitro-->>Browser: SSE stream
```

The engine never blocks on a single full response — it yields events continuously. The UI consumes them to populate the search tree and report panel in real time, which is the feature advertised as "Realtime feedback" in [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md).

## 5. Streaming JSON Parsing

Because providers do not return strict Structured Outputs, the engine relies on `parseStreamingJson` in `shared/utils/json.ts`. It walks the AI SDK's `fullStream`, accumulates `text-delta` chunks, strips Markdown fences, and re-parses after every delta. It yields three event types:

| Event | Meaning |
|-------|---------|
| `reasoning` | Forwarded `reasoning` chunk (e.g. DeepSeek R1 thoughts). |
| `object`    | Partial JSON object that already satisfies the validator. |
| `error` / `bad-end` | Parse failure or upstream error. |

Source: [shared/utils/json.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/utils/json.ts).

This mechanism explains the failure mode reported in [issue #69](https://github.com/AnotiaWang/deep-research-web-ui/issues/69) — when the report JSON is truncated or malformed, the final report collapses to a single model summary because the loop has no further context to expand.

## 6. Runtime Configuration Contract

The split between private and public runtime config is enforced by `shared/types/config.ts`:

- **`ServerRuntimeConfig`** carries secrets (`aiApiKey`, `webSearchApiKey`) and provider base URLs — only available server-side.
- **`PublicRuntimeConfig`** exposes only non-secret knobs (`aiProvider`, `aiModel`, `aiContextSize`, `webSearchConcurrencyLimit`, `webSearchSearchLanguage`, `tavilyAdvancedSearch`, `tavilySearchTopic`, `googlePseId`, `serverMode`) so the client can render the settings UI without leaking credentials.

Source: [shared/types/config.ts](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/shared/types/config.ts).

This separation was the request behind [issue #8](https://github.com/AnotiaWang/deep-research-web-ui/issues/8) and is what enables the single-Docker-command deployment shown in [README.md](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/README.md).

Static deployments (e.g. EdgeOne Pages via [edgeone.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/edgeone.json)) build with `pnpm generate:optimize` and do **not** run Nitro routes, so Server Mode APIs are unavailable there — users must stay in Client Mode.

## 7. Common Failure Modes

- **Retry does nothing** ([issue #71](https://github.com/AnotiaWang/deep-research-web-ui/issues/71)) — retry state is local to the failed node and may not re-enter the SSE stream after a transport error.
- **Azure OpenAI base URL mis-construction** ([issue #70](https://github.com/AnotiaWang/deep-research-web-ui/issues/70)) — the engine concatenates `apiBase` naively, ignoring Azure's `api-version` query parameter.
- **CORS rejection** — surfaced by the `requestBlockedByCORS` toast; the engine cannot proxy AI calls in Client Mode. Source: [i18n/en.json](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/i18n/en.json).

## See Also

- [Configuration & Server Mode](README.md)
- [Deep Research (upstream library)](https://github.com/dzhng/deep-research)
- Community issues: [#8 (env vars)](https://github.com/AnotiaWang/deep-research-web-ui/issues/8), [#73 (Firecrawl rate limit)](https://github.com/AnotiaWang/deep-research-web-ui/issues/73), [#79 (API support)](https://github.com/AnotiaWang/deep-research-web-ui/issues/79).

---

<a id='page-4'></a>

## Frontend Components, Search Visualization & History

### Related Pages

Related topics: [Research Engine, API Endpoints & Data Flow](#page-3)

<details>
<summary>Related Source Files</summary>

The following source files were used to generate this page:

- Source: [app/pages/index.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/pages/index.vue)
- Source: [app/components/ResearchForm.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/components/ResearchForm.vue)
- Source: [app/components/ResearchFeedback.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/components/ResearchFeedback.vue)
- Source: [app/components/DeepResearch/DeepResearch.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/components/DeepResearch/DeepResearch.vue)
- Source: [app/components/DeepResearch/SearchFlow.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/components/DeepResearch/SearchFlow.vue)
- Source: [app/components/DeepResearch/SearchNode.vue](https://github.com/AnotiaWang/deep-research-web-ui/blob/main/app/components/DeepResearch/SearchNode.vue)
</details>

Error with Openai API: Error code: 500 - {'type': 'error', 'error': {'type': 'server_error', 'message': 'unknown error, 999 (1000)', 'http_code': '500'}, 'request_id': '068d5b03c22107371180a77312fdee59'}

Please check that you have set the OPENAI_API_KEY environment variable with a valid API key.

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Pitfall Log

Project: AnotiaWang/deep-research-web-ui

Summary: Found 14 structured pitfall item(s), including 1 high/blocking item(s). Top priority: Security or permission risk - Security or permission risk requires verification.

## 1. Security or permission risk - Security or permission risk requires verification

- Severity: high
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/AnotiaWang/deep-research-web-ui/issues/8

## 2. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: runtime_trace
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Repro command: `docker run -p 3000:3000 -e NUXT_PUBLIC_SERVER_MODE=true -e NUXT_AI_API_KEY=your-ai-api-key -e NUXT_WEB_SEARCH_API_KEY=your-search-api-key -e NUXT_PUBLIC_AI_PROVIDER=openai-compatible -e NUXT_PUBLIC_AI_MODEL=gpt-4o-mini -e NUXT_PUBLIC_WEB_SEARCH_PROVIDER=tavily anotia/deep-research-web:latest`
- Evidence: identity.distribution | https://github.com/AnotiaWang/deep-research-web-ui

## 3. Installation risk - Installation risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/AnotiaWang/deep-research-web-ui/issues/43

## 4. Configuration risk - Configuration risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.host_targets | https://github.com/AnotiaWang/deep-research-web-ui

## 5. Capability evidence risk - Capability evidence risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: README/documentation is current enough for a first validation pass.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: capability.assumptions | https://github.com/AnotiaWang/deep-research-web-ui

## 6. Runtime risk - Runtime risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a runtime risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/AnotiaWang/deep-research-web-ui/issues/71

## 7. Runtime risk - Runtime risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a runtime risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/AnotiaWang/deep-research-web-ui/issues/70

## 8. Maintenance risk - Maintenance risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/AnotiaWang/deep-research-web-ui

## 9. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: downstream_validation.risk_items | https://github.com/AnotiaWang/deep-research-web-ui

## 10. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: no_demo
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: risks.scoring_risks | https://github.com/AnotiaWang/deep-research-web-ui

## 11. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/AnotiaWang/deep-research-web-ui/issues/73

## 12. Security or permission risk - Security or permission risk requires verification

- Severity: medium
- Evidence strength: source_linked
- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: community_evidence:github | https://github.com/AnotiaWang/deep-research-web-ui/issues/79

## 13. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: issue_or_pr_quality=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/AnotiaWang/deep-research-web-ui

## 14. Maintenance risk - Maintenance risk requires verification

- Severity: low
- Evidence strength: source_linked
- Finding: release_recency=unknown。
- User impact: May increase setup, validation, or first-run risk for the user.
- Evidence: evidence.maintainer_signals | https://github.com/AnotiaWang/deep-research-web-ui

<!-- canonical_name: AnotiaWang/deep-research-web-ui; human_manual_source: deepwiki_human_wiki -->
