# Chat Nodes

> Applies to: ChengOS v0.2.0+ ｜ Last verified: 2026-09-25 ｜ Source: `crates/cheng-nodes/src/nodes/builtin/chat`

`chat/input` and `chat/output` are the two ends of a conversational workflow: one receives the incoming
message and session identity, the other returns the reply on the same session. `chat/history_search`
is the read side — list conversations, search messages, or pull the messages around one hit — and it
is what lets an agent answer questions about what was already said without keeping the entire history
in the prompt.

## Chat Input Node — `chat/input`

Receive multi-modal input (text, images, files, etc.), process and send to downstream nodes

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `raw_input` | string (port) | ✅ | — | Raw input payload (JSON format). Connection port, not a form field. Control: `textarea` |
| `user_message_rich` | object (port) | — | `null` | Optional rich user message from upstream nodes. Connection port, not a form field. |
| `context` | object | — | `null` | Optional AgentContext restored before this workflow execution |
| `conversation_id` | string (port) | — | `null` | Conversation ID (optional), generated at entry and passed through to all downstream nodes. Connection port, not a form field. |
| `workspace_id` | string (port) | — | `null` | Workspace ID (optional), used for per-workspace chat isolation. Connection port, not a form field. |
| `document_id` | string (port) | — | `null` | Document ID (optional), injected by document page and passed through ambient context to downstream nodes. Connection port, not a form field. |
| `stream_mode` | boolean | — | `false` | Enable streaming send. Control: `switch` |
| `enable_ocr` | boolean | — | `false` | Enable OCR for images. Control: `switch` |
| `merge_strategy` | enum | — | `per_file` | Multi-input merge strategy. Control: `select`. Options: `merge_all` (合并所有消息为一个包), `per_file` (每个文件单独一个包), `per_line` (每行单独一个包) |
| `max_file_size_mb` | integer | — | `50` | Maximum file size (MB). Control: `number` |
| `model_override` | string | — | `null` | Model override (format: credential_id::model_name) |

### Outputs

| Field | Type | Description |
|---|---|---|
| `agent_context` | object (port) | AgentContext wrapper, connectable directly to agent/llm context port. Connection port, not a form field. |
| `user_message` | string (port) | User message text. Connection port, not a form field. |
| `user_message_rich` | object (port) | Structured user message with multimodal parts. Connection port, not a form field. |
| `conversation_id` | string (port) | Conversation ID (passed through to downstream nodes). Connection port, not a form field. |
| `workspace_id` | string (port) | Workspace ID (passed through for per-workspace isolation). Connection port, not a form field. |
| `document_id` | string (port) | Document ID (passed through ambient context to downstream document nodes). Connection port, not a form field. |
| `stats` | object | Processing statistics |
| `ui_event` | enum | UI event |
| `model_override` | string | Model override (format: credential_id::model_name) |
| `attachments_json` | string (port) | Attachments JSON array, connectable directly to io/file_upload.files_json. Connection port, not a form field. |

## Chat Output Node — `chat/output`

Receive message packets and render to chat interface, supports streaming display, virtualization and message export

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `context` | object (port) | — | `""` | Agent final reply text or AgentContext (auto extracts text). Connection port, not a form field. |
| `artifacts` | object (port) | — | `[]` | Artifact reference(s) to render as media attachments. Connection port, not a form field. |
| `trace` | string (port) | — | `null` | Agent execution trace (thinking process). Connection port, not a form field. |
| `theme` | enum | — | `system` | Display theme. Control: `select`. Options: `light`, `dark`, `system` |
| `autoscroll` | boolean | — | `true` | Auto scroll to latest message. Control: `switch` |
| `keep_messages` | integer | — | `1000` | Maximum messages to keep in memory. Control: `number` |
| `virtualize_threshold` | integer | — | `100` | Enable virtualization when message count exceeds this value. Control: `slider` |
| `display_format` | enum | — | `standard` | Message display format. Control: `select`. Options: `compact` (紧凑模式), `standard` (标准模式), `detailed` (详细模式) |
| `show_timestamp` | boolean | — | `true` | Show message timestamp. Control: `switch` |

### Outputs

| Field | Type | Description |
|---|---|---|
| `reply` | string | Assistant final reply text content |
| `trace` | string | Agent execution trace (thinking process) |
| `ui_events` | array&lt;enum&gt; | UI events to send to frontend |
| `message_count` | integer | Current total messages retained |
| `virtualized` | boolean | Whether virtualization rendering is enabled |
| `stats` | object | Processing statistics |

## Chat History Search — `chat/history_search`

Search past chat conversations across the workspace. Exposed as an on-demand tool to LLM/Agent — NOT a default context provider. Do not use for file paths or file contents; use file tools for those.

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `action` | enum | — | `search_messages` | What to do: list_conversations \| search_messages \| get_conversation_messages \| get_message_context. Options: `list_conversations` (列出 workspace 内活跃过的会话（按 updated_at desc）。), `search_messages` (按关键字 + 时间范围检索消息。), `get_conversation_messages` (取指定会话最近 N 条消息。), `get_message_context` (以某条消息为中心扩展上下文。) |
| `workspace_id` | string | — | `null` | Workspace UUID. Falls back to execution metadata if absent. |
| `target_conversation_id` | string | — | `null` | Restrict the search to a specific conversation. Distinct from the current session's conversation_id so cross-session searches are possible. |
| `query` | string | — | `null` | Keyword (case-insensitive, ILIKE-style). |
| `time_range` | enum | — | `last_week` | 时间范围。默认 `last_week`。 Options: `last_hour`, `last_day`, `last_week`, `last_month`, `all_time` |
| `limit` | integer | — | `10` | 单次返回上限。 |
| `message_id` | string | — | `null` | 锚点 message_id（仅 `get_message_context` 使用）。 |
| `context_before` | integer | — | `2` | 锚点之前要带出多少条消息。 |
| `context_after` | integer | — | `2` | 锚点之后要带出多少条消息。 |
| `snippet_max_chars` | integer | — | `200` | snippet 最大字符数（按字符截断，避免单条消息撑爆上下文）。 |

### Outputs

| Field | Type | Description |
|---|---|---|
| `found` | boolean | Found |
| `no_results_found` | boolean | No Results Found |
| `total` | integer | Total |
| `results` | array&lt;object&gt; | Results |
| `summary` | string | Summary |
| `suggestion` | string | Suggestion |
| `call_limit_reached` | boolean | 当本次执行的搜索配额已用尽时为 true，调用方应避免再次发起。 |

## Next steps

- [Embedded Chat in the Editor](/docs/chat-embedded)
- [Channel Routing & Session Mapping](/docs/chat-channel-routing)
- [Hub Nodes](/docs/nodes-hubs)
