# HTTP & Web Nodes

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

Reaching outside the system. `tools/http` is the raw request; `tools/web` sits one level higher with
operations for fetching, extracting readable article text, crawling, and downloading — prefer it when
you want content rather than a response body. `tools/fetch_repository` pulls skill sources, `tools/ssh`
runs a remote command, and `tools/mail` covers send and read. Both `tools/http` and `tools/web` offer a
manual mode where the workflow supplies every parameter and an LLM mode where the model fills them in.
The browser node lives behind an optional build feature and is not part of a default build.

## HTTP Tool — `tools/http`

Send HTTP requests to specified URL, supports manual mode and LLM mode

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `credential_id` | string | — | `null` | HTTP authentication credential ID (optional, for Bearer Token or Basic Auth). Control: `credential-select` |
| `mode` | enum | — | `manual` | Execution mode: Manual=user fills all parameters, Llm=LLM auto-fills parameters. Control: `select`. Options: `manual` (手动模式：用户在前端填写所有参数), `llm` (LLM 模式：LLM 通过 ReAct 调用时填充参数) |
| `url` | string | — | `null` | Target URL (filled by LLM in LLM mode, or by user in manual mode) |
| `method` | enum | — | `GET` | HTTP method. Control: `select`. Options: `GET`, `POST`, `PUT`, `DELETE`, `PATCH` |
| `headers` | object | — | `null` | Custom request headers (optional) |
| `body` | string | — | `null` | Request body (JSON string or form data). Control: `code-editor` |
| `timeout_seconds` | integer | — | `30` | Timeout in seconds. Control: `number` |
| `body_artifact` | object | — | `null` | Artifact reference used as the request body (preferred over inline body for large uploads) |
| `body_artifact_uri` | string | — | `null` | artifact:// URI used as the request body |
| `request_profile` | enum | — | `general` | Static profile: general (default) or discovery (read-only HTTPS GET inspection). Options: `general` (General-purpose HTTP (backward compatible).), `discovery` (Read-only discovery: HTTPS GET only, no credentials/headers/body.) |

### Outputs

| Field | Type | Description |
|---|---|---|
| `mode` | string | Execution mode |
| `timeout_seconds` | integer | Timeout in seconds |
| `status_code` | integer | HTTP response status code |
| `body` | string | Deprecated bounded inline response text; large/binary responses use body_artifact |
| `body_artifact` | object | Artifact holding the complete response body when large or binary |
| `body_preview` | string | Bounded, LLM-facing preview of the response body |
| `body_bytes` | integer | Observed/declared total response body size in bytes (may be unknown for chunked responses) |
| `retained_bytes` | integer | Bytes actually retained/stored; distinguishes stored size from the remote total when truncated |
| `location` | string | Normalized, validated redirect target for a 3xx response (automatic redirects stay disabled) |
| `body_mime_type` | string | Response body MIME type |
| `body_sha256` | string | Response body content hash |
| `download_filename` | string | Suggested filename for the response payload |
| `body_truncated` | boolean | Whether the inline body/preview was truncated relative to the full response |
| `headers` | object | Response headers |
| `elapsed_ms` | integer | Request elapsed time in milliseconds |
| `credential_used` | boolean | Whether credential authentication was used |

## Web Tool — `tools/web`

Comprehensive web suite: HTTP requests, page reading, metadata, extraction, articles, downloads, crawling, and search

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `mode` | enum | — | `manual` | Execution mode — mirrors the concept used by `tools/http`. Options: `manual` (Manual mode: the user/workflow supplies every parameter.), `llm` (LLM mode: the agent may fill selected fields during tool use.) |
| `operation` | enum | — | `fetch` | The nine supported web operations. Options: `request`, `check`, `fetch`, `metadata`, `extract`, `article`, `download`, `crawl`, `search` |
| `credential_id` | string | — | `null` | Credential Id |
| `url` | string | — | `null` | Url |
| `method` | enum | — | `GET` | HTTP methods supported by `request` / `check`. Options: `GET`, `HEAD`, `POST`, `PUT`, `PATCH`, `DELETE` |
| `headers` | object | — | `null` | Headers |
| `body` | string | — | `null` | Body |
| `query` | string | — | `null` | Query |
| `selector` | string | — | `null` | Selector |
| `extract_mode` | enum | — | `text` | Extraction mode for the `extract` operation. Options: `text`, `html`, `markdown`, `attr`, `json` |
| `attribute_name` | string | — | `null` | Attribute Name |
| `output_format` | enum | — | `markdown` | Output format for `fetch` and per-page crawl conversion. Options: `raw_html`, `text`, `markdown` |
| `include_headers` | boolean | — | `false` | Include Headers |
| `header_filter` | array | — | `null` | Header Filter |
| `save_path` | string | — | `null` | Save Path |
| `allowed_mime_types` | array | — | `null` | Allowed Mime Types |
| `overwrite` | boolean | — | `false` | Overwrite |
| `max_download_bytes` | integer | — | `52428800` | Independent size cap for `download` (downloads are typically larger than in-context response bodies, so they get their own limit). |
| `max_response_bytes` | integer | — | `1048576` | Max Response Bytes |
| `page_character_limit` | integer | — | `20000` | Page Character Limit |
| `max_total_bytes` | integer | — | `200000` | Max Total Bytes |
| `max_total_tokens` | integer | — | `50000` | Max Total Tokens |
| `max_depth` | integer | — | `2` | Max Depth |
| `max_pages` | integer | — | `20` | Max Pages |
| `same_origin_only` | boolean | — | `true` | Same Origin Only |
| `allowed_domains` | array | — | `null` | Allowed Domains |
| `respect_robots` | boolean | — | `true` | Respect Robots |
| `crawl_delay_ms` | integer | — | `500` | Crawl Delay Ms |
| `concurrency` | integer | — | `2` | Concurrency |
| `search_provider` | enum | — | `tavily` | Search provider. Tavily requires credential_id; SearXNG uses search_base_url. Control: `select`. Options: `tavily`, `searxng` |
| `search_base_url` | string | — | `null` | Static base URL for self-hosted search providers (e.g. SearXNG). Treated as operator configuration, never an LLM-controlled arbitrary endpoint. |
| `max_results` | integer | — | `5` | Max Results |
| `search_page` | integer | — | `1` | Search Page |
| `search_include_content` | boolean | — | `false` | Search Include Content |
| `timeout_seconds` | integer | — | `30` | Timeout Seconds |

### Outputs

| Field | Type | Description |
|---|---|---|
| `mode` | string | Mode |
| `operation` | string | Operation |
| `url` | string | Url |
| `final_url` | string | Final Url |
| `status_code` | integer | Status Code |
| `content_type` | string | Content Type |
| `elapsed_ms` | integer | Elapsed Ms |
| `body_truncated` | boolean | Body Truncated |
| `result_truncated` | boolean | Result Truncated |
| `spa_detected` | boolean | Spa Detected |
| `warnings` | array&lt;string&gt; | Warnings |
| `credential_used` | boolean | Credential Used |
| `result` | any | Operation-specific payload (see the per-operation result structs). |

## Fetch Skill Source — `tools/fetch_repository`

Fetch a remote skill source (git repo, single HTTP URL, or pasted content) into a persistent workspace skill package and return its package_path.

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `source_type` | string | — | `repository` | repository \| url \| pasted_text \| skill_md |
| `source_location` | string | — | `""` | Repository clone URL, HTTPS document URL, or short identifier for pasted content (used only as a label when source_type is pasted_text / skill_md). |
| `source_content` | string | — | `null` | Inline file content. Required for `pasted_text` / `skill_md`, ignored for `repository` / `url`. |
| `branch` | string | — | `null` | Git branch (optional, repository only) |
| `harvest_mode` | string | — | `skill_package` | skill_package (default) \| source_tree — how much of a cloned repository to select. |
| `llm_inline_max_bytes` | integer | — | `50000` | Deprecated and ignored. Output is always artifact-backed with a bounded llm_preview; this value no longer changes the result. |
| `allow_insecure_schemes` | boolean | — | `false` | Permit http/ssh/git URLs (default: https only) |
| `legacy_inline_files` | boolean | — | `false` | Deprecated compatibility: also emit full `files[].content` inline (under a strict total byte cap). Off by default — normal execution returns file artifacts plus a bounded `llm_preview`. |
| `sandbox_root` | string | — | `null` | Engine-injected sandbox root (same authority as `file_ops_hub`). Not LLM-callable — the workflow engine injects this via `apply_effective_sandbox_root` so `fetch_repository` writes into the same root that `file_ops_hub` reads from. |

### Outputs

| Field | Type | Description |
|---|---|---|
| `success` | boolean | Success |
| `package_path` | string | Workspace-relative package directory shared with `file_ops_hub` and `validate_skill_spec`, for example `skills/example-skill`. |
| `files` | array&lt;object&gt; | Deprecated compatibility: full file payloads inline. Empty unless `legacy_inline_files` is set (and under a strict byte cap). Prefer `files_manifest` / `repository_artifact`. |
| `files_manifest` | array&lt;object&gt; | Per-file artifact metadata (path, size, mime, artifact ref). Downstream nodes resolve each artifact to recover the complete file content. |
| `existing_files` | array&lt;string&gt; | Existing workspace-relative files when the target package already exists. This informational branch does not create new artifacts or read file contents. |
| `repository_artifact` | object | The complete fetched source as a single JSON bundle artifact (`{ files: [{ path, content }] }`), for whole-repository consumers. |
| `manifest_artifact` | object | Optional artifact holding the full manifest when it is large. |
| `llm_preview` | string | Bounded, LLM-facing preview: source URL, commit, per-file sizes, and small excerpts within a budget. Never the full file contents. |
| `total_files` | integer | Total number of harvested files. |
| `total_bytes` | integer | Total bytes across all harvested files. |
| `warnings` | array&lt;string&gt; | Structured warnings for omitted files (binary, oversized, excluded, secret) and global truncation (caps reached). Never contains file contents. |
| `llm_text` | string | Deprecated: legacy text rendering. Now mirrors `llm_preview` (bounded). |
| `source_snapshot_artifact` | object | Trusted, complete source snapshot artifact (every accepted regular file, byte-for-byte). This is the ONLY reference the Agent forwards to `tools/write_skill_package`; it never reconstructs source bytes itself. |
| `source_manifest` | array&lt;object&gt; | Complete (or inline-bounded) manifest of the source snapshot: path, kind, size, SHA-256, and text-readability per file. |
| `source_manifest_artifact` | object | Full manifest as a JSON artifact when it is too large to inline. |
| `source_file_count` | integer | Number of files in the source snapshot. |
| `source_total_bytes` | integer | Total bytes across the source snapshot. |
| `source_scan_truncated` | boolean | True only if the snapshot could not be fully represented. When true, activation must be refused — a partial tree is never a self-contained Skill. |
| `commit_hash` | string | Commit Hash |
| `source_url` | string | Source Url |
| `error` | string | Error |

## SSH Executor — `tools/ssh`

Execute commands on the SSH host configured on this node. The host, port, and credential are static canvas configuration; when used as an LLM tool, provide only the command (and optional working_dir). Built-in approval gate risk-classifies commands and surfaces rejection reasons (rejected/skipped/timed_out/policy_denied) so agents can replan correctly.

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `host` | string | ✅ | — | Remote host (hostname or IP) |
| `port` | integer | — | `22` | Remote SSH port. Control: `number` |
| `credential_id` | string | — | `null` | SSH credential — private key or password (resolved via CredentialRepository). Control: `credential-select` |
| `command` | string | — | `""` | Command to execute on the remote host. Control: `code-editor` |
| `working_dir` | string | — | `null` | Optional cwd before executing the command |
| `timeout_ms` | integer | — | `30000` | Per-command execution timeout in milliseconds. Control: `number` |
| `strict_host_key_checking` | boolean | — | `true` | TOFU: first-connect host key prompts user approval; subsequent connects use the trusted key. Disable only for ad-hoc testing. Control: `switch` |
| `read_only_mode` | boolean | — | `false` | Hard policy: when enabled, any non-readonly command is denied without going through approval. Control: `switch` |
| `approval_required_at_or_above` | enum | — | `medium` | Risk threshold for triggering the approval gate (medium by default). Control: `select`. Options: `low`, `medium`, `high`, `critical` |
| `approval_timeout_secs` | integer | — | `300` | Seconds to wait for the user's decision before timing out (default 300). Control: `number` |

### Outputs

| Field | Type | Description |
|---|---|---|
| `success` | boolean | True iff the command executed and returned 0 |
| `exit_code` | integer | Remote process exit code |
| `stdout` | string | Captured stdout |
| `stderr` | string | Captured stderr |
| `duration_ms` | integer | Wall-clock execution time |
| `host` | string | Target host echoed back for traceability |
| `command` | string | Command echoed back for traceability |
| `risk_level` | string | Classified risk for this command |
| `rejection_type` | string | Distinguishes execute / approval / policy outcomes |
| `reason` | string | Reason text from user or policy |
| `approval_request_id` | string | UUID matching the approval bus event |
| `observation` | string | Agent-facing observation text with [APPROVAL_*] prefixes |

## Mail Tool — `tools/mail`

Operate real emails via IMAP/SMTP protocols: send, read, search, move, mark, reply, forward and more

### Inputs

| Field | Type | Required | Default | Description |
|---|---|:-:|---|---|
| `imap_credential_id` | string | — | `null` | IMAP credential for receiving operations (read, search, move, delete etc. - ListEmails/SearchEmails/GetEmail/MoveEmail etc.). Control: `credential-select` |
| `smtp_credential_id` | string | — | `null` | SMTP credential for sending operations (SendEmail/ReplyEmail/ForwardEmail). Control: `credential-select` |
| `operation` | enum | — | — | Email operation type to execute. Control: `select`. Options: `send_email` (发送邮件（需 SMTP 配置）), `list_emails` (获取邮件列表（需 IMAP 配置）), `search_emails` (搜索邮件（需 IMAP 配置）), `get_email` (获取邮件详情及正文（需 IMAP 配置）), `move_email` (移动邮件到指定文件夹), `copy_email` (复制邮件到指定文件夹), `delete_email` (删除邮件), `mark_as_read` (标记邮件为已读), `mark_as_unread` (标记邮件为未读), `list_folders` (列出所有邮件文件夹), `reply_email` (回复邮件（需 IMAP + SMTP 配置）), `forward_email` (转发邮件（需 IMAP + SMTP 配置）) |
| `display_name` | string | — | — | Sender display name (e.g. John Doe), leave empty to show only email address |
| `folder` | string | — | `INBOX` | Mail folder name (default INBOX, sent usually Sent or [Gmail]/Sent Mail) |
| `page` | integer | — | `1` | Page number starting from 1 (default 1, newest emails on page 1) |
| `page_size` | integer | — | `20` | Number of emails per page (default 20, max 50) |
| `to` | string | — | — | Recipient email address, multiple addresses separated by commas |
| `cc` | string | — | — | CC email address, multiple addresses separated by commas |
| `bcc` | string | — | — | BCC email address, multiple addresses separated by commas |
| `subject` | string | — | — | Email subject |
| `body` | string | — | — | Email body content |
| `format` | enum | — | — | Body format: text (plain text), html (HTML), both (send both, recommended). Options: `text` (纯文本), `html` (HTML 格式), `both` (同时发送纯文本和 HTML（推荐，兼容性最好）) |
| `query` | string | — | — | IMAP search query (FROM, SUBJECT, UNSEEN, SINCE, etc.) |
| `email_id` | string | — | — | Email unique identifier (obtained from id field in ListEmails/SearchEmails results) |
| `target_folder` | string | — | — | Target folder name for moving or copying emails (e.g. Archive, Trash, [Gmail]/All Mail) |
| `attachments` | array&lt;object&gt; | — | — | Attachments to send (artifact refs preferred; small inline text allowed) |
| `include_attachments` | boolean | — | `false` | GetEmail: download and persist attachment bodies as artifacts |

### Outputs

| Field | Type | Description |
|---|---|---|
| `success` | boolean | Whether operation succeeded |
| `message` | string | Operation result description |
| `emails` | array&lt;object&gt; | Email list |
| `folders` | array&lt;string&gt; | Mail folder name list |
| `page` | integer | Current page number |
| `count` | integer | Number of emails returned this time |
| `total_count` | integer | Total email count in folder (only provided by ListEmails) |

## Next steps

- [System & Safety Nodes](/docs/nodes-utils-system)
- [Code Index Nodes](/docs/nodes-code-index)
- [REST API Overview](/docs/api-rest-overview)
