{"id":"9583f365-e1d9-45b4-9fdc-08992cf727cd","entityType":"agent","slug":"clawhub-lunarcache-skill-for-ragflow","name":"RAGFlow Skill","canonicalUrl":"https://www.xpersona.co/agent/clawhub-lunarcache-skill-for-ragflow","canonicalPath":"/agent/clawhub-lunarcache-skill-for-ragflow","generatedAt":"2026-10-09T23:50:36.874Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":null},"description":"Manage everyday RAGFlow datasets, retrieval, chat, and agents. Skill: RAGFlow Skill Owner: lunarcache Summary: Manage everyday RAGFlow datasets, retrieval, chat, and agents. Tags: latest:3.0.0 Version history: v3.0.0 | 2026-09-25T02:38:34.249Z | user Require explicit authorization flags for destructive requests; harden embedded HTML and widget messages; validate multipart upload names. RAGFlow v0.27.2 APIs only. v2.0.1 | 2026-09-25T02:14:38.739Z | user Remove compatibility analy","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 2.2K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17bykgzpmk1mf077wb7zt08kd85n0rz:skill-for-ragflow","sourceUrl":"https://clawhub.ai/lunarcache/skill-for-ragflow","homepage":"https://clawhub.ai/lunarcache/skills/skill-for-ragflow","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/lunarcache/skill-for-ragflow","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/lunarcache/skills/skill-for-ragflow","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":67,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Manage everyday RAGFlow datasets, retrieval, chat, and agents. Skill: RAGFlow Skill Owner: lunarcache Summary: Manage everyday RAGFlow datasets, retrieval, chat"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":null},"stars":null,"forks":null,"downloads":2242,"packageName":null,"latestVersion":"3.0.0","tractionLabel":"2.2K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T17:08:31.525Z","lastCrawledAt":"2026-10-09T17:08:31.525Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T17:08:31.525Z","lastVerifiedAt":null,"highlights":[{"version":"3.0.0","createdAt":"2026-09-25T02:38:34.249Z","changelog":"Require explicit authorization flags for destructive requests; harden embedded HTML and widget messages; validate multipart upload names. RAGFlow v0.27.2 APIs only.","fileCount":17,"zipByteSize":64254},{"version":"2.0.1","createdAt":"2026-09-25T02:14:38.739Z","changelog":"Remove compatibility analysis and API audit records from the distributed Skill package. Keep maintenance records in the repository only and remove their package references. Runtime behavior unchanged; targets RAGFlow v0.27.2.","fileCount":17,"zipByteSize":62426},{"version":"2.0.0","createdAt":"2026-09-25T02:05:01.870Z","changelog":"RAGFlow v0.27.2 support. Remove obsolete model-discovery fallback and compatibility parameters; require current retrieval and chat parameters. Add KNN/rerank pagination, filtering, highlighting and compilation controls. Preserve model provider instances and expose usable identifiers. Fix binary download/preview and add --output. Correct connector source payloads; document Sitemap and WebDAV CA configuration. Simplify skill guidance and include a source-pinned API audit. Validated with 61 local tests.","fileCount":18,"zipByteSize":65954},{"version":"1.8.0","createdAt":"2026-08-25T00:18:41.823Z","changelog":"v1.8.0 (RAGFlow v0.27.0): Updated references to v0.27.0. list-models now uses GET /api/v1/models (legacy /v1/llm/my_llms removed in v0.27.0) with fallback for older servers. list-connectors/create-connector corrected to tenant-scoped /api/v1/connectors (--dataset no longer required). Documented v0.27.0 connector types (GitLab, Bitbucket, Notion, GCS) and provider instance GET/PUT routes.","fileCount":17,"zipByteSize":62437},{"version":"1.7.0","createdAt":"2026-08-03T01:40:54.559Z","changelog":"v1.7.0 (RAGFlow v0.26.4): focus on daily workflows; add chunk lookup, metadata updates, session management, GraphRAG and health diagnostics; reject invalid CLI options; improve credential handling; tighten skill guidance and examples.","fileCount":17,"zipByteSize":61957},{"version":"1.6.0","createdAt":"2026-07-09T00:38:56.431Z","changelog":"v1.6.0 (RAGFlow v0.26.4): updated route notes; switched update-chunk to PATCH; added ingestion-pipeline and document-graph commands; added chat legacy flag.","fileCount":17,"zipByteSize":61122},{"version":"1.5.0","createdAt":"2026-06-17T09:41:32.377Z","changelog":"v1.5.0 (RAGFlow v0.26.0): Updated all references/route-shape notes to v0.26.0. Added model-provider management commands (/api/v1/providers) and tenant model commands (/api/v1/models). List endpoints now clamp page_size to 100 (v0.26.0 server cap) with a warning. Documented new connector types (OneDrive, Outlook, Teams, Slack, SharePoint, Salesforce, Azure Blob).","fileCount":17,"zipByteSize":59598},{"version":"1.4.0","createdAt":"2026-06-08T01:24:27.413Z","changelog":"v1.4.0 (RAGFlow v0.25.6): Chat session history behavior changed - default now appends only latest message, use --pass-all-history for full history replacement. New features: preview-document command, --canvas-type for create/update-agent, --chat-template-kwargs for agent-chat, conversation_id alias, Browser component in agent DSL. Fixed: openai.yaml stale v0.25.2 reference, agent chat route documentation (singular->plural).","fileCount":17,"zipByteSize":55033}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17bykgzpmk1mf077wb7zt08kd85n0rz:skill-for-ragflow","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T23:50:36.871Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-lunarcache-skill-for-ragflow/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":null},"readme":"Skill: RAGFlow Skill\n\nOwner: lunarcache\n\nSummary: Manage everyday RAGFlow datasets, retrieval, chat, and agents.\n\nTags: latest:3.0.0\n\nVersion history:\n\nv3.0.0 | 2026-09-25T02:38:34.249Z | user\n\nRequire explicit authorization flags for destructive requests; harden embedded HTML and widget messages; validate multipart upload names. RAGFlow v0.27.2 APIs only.\n\nv2.0.1 | 2026-09-25T02:14:38.739Z | user\n\nRemove compatibility analysis and API audit records from the distributed Skill package. Keep maintenance records in the repository only and remove their package references. Runtime behavior unchanged; targets RAGFlow v0.27.2.\n\nv2.0.0 | 2026-09-25T02:05:01.870Z | user\n\nRAGFlow v0.27.2 support. Remove obsolete model-discovery fallback and compatibility parameters; require current retrieval and chat parameters. Add KNN/rerank pagination, filtering, highlighting and compilation controls. Preserve model provider instances and expose usable identifiers. Fix binary download/preview and add --output. Correct connector source payloads; document Sitemap and WebDAV CA configuration. Simplify skill guidance and include a source-pinned API audit. Validated with 61 local tests.\n\nv1.8.0 | 2026-08-25T00:18:41.823Z | user\n\nv1.8.0 (RAGFlow v0.27.0): Updated references to v0.27.0. list-models now uses GET /api/v1/models (legacy /v1/llm/my_llms removed in v0.27.0) with fallback for older servers. list-connectors/create-connector corrected to tenant-scoped /api/v1/connectors (--dataset no longer required). Documented v0.27.0 connector types (GitLab, Bitbucket, Notion, GCS) and provider instance GET/PUT routes.\n\nv1.7.0 | 2026-08-03T01:40:54.559Z | user\n\nv1.7.0 (RAGFlow v0.26.4): focus on daily workflows; add chunk lookup, metadata updates, session management, GraphRAG and health diagnostics; reject invalid CLI options; improve credential handling; tighten skill guidance and examples.\n\nv1.6.0 | 2026-07-09T00:38:56.431Z | user\n\nv1.6.0 (RAGFlow v0.26.4): updated route notes; switched update-chunk to PATCH; added ingestion-pipeline and document-graph commands; added chat legacy flag.\n\nv1.5.0 | 2026-06-17T09:41:32.377Z | user\n\nv1.5.0 (RAGFlow v0.26.0): Updated all references/route-shape notes to v0.26.0. Added model-provider management commands (/api/v1/providers) and tenant model commands (/api/v1/models). List endpoints now clamp page_size to 100 (v0.26.0 server cap) with a warning. Documented new connector types (OneDrive, Outlook, Teams, Slack, SharePoint, Salesforce, Azure Blob).\n\nv1.4.0 | 2026-06-08T01:24:27.413Z | user\n\nv1.4.0 (RAGFlow v0.25.6): Chat session history behavior changed - default now appends only latest message, use --pass-all-history for full history replacement. New features: preview-document command, --canvas-type for create/update-agent, --chat-template-kwargs for agent-chat, conversation_id alias, Browser component in agent DSL. Fixed: openai.yaml stale v0.25.2 reference, agent chat route documentation (singular->plural).\n\nv1.3.0 | 2026-05-25T02:05:03.272Z | user\n\nv1.3.0: Upgrade to RAGFlow v0.25.5. Added agent tags management, document download, connector operations, and RAPTOR processing. Updated getDataset to use direct endpoint.\n\nv1.2.6 | 2026-05-14T06:45:20.481Z | user\n\nv1.2.6: Added security best practices documentation. New Security Notes section covers HTTPS usage, least-privilege API keys, and secret protection. Updated troubleshooting with security-related guidance.\n\nv1.2.5 | 2026-05-14T06:16:27.359Z | user\n\nv1.2.5: Removed RAGFLOW_WEB_TOKEN dependency. The /v1/llm/my_llms endpoint now accepts RAGFLOW_API_KEY authentication directly, simplifying configuration.\n\nv1.2.4 | 2026-05-14T05:41:11.266Z | user\n\nv1.2.4: Updated to support RAGFlow v0.25.2. Changes include: embedded website support (embed-code, embed-info, embed-chat, embed-agent-chat commands), upload-documents display-name=path format, delete-system-token stdin/file support, model identifier clarification (model@provider format), URL normalization for bare RAGFLOW_URL hosts.\n\nv1.2.3 | 2026-05-06T05:51:59.017Z | user\n\nAvoid passing system tokens in argv: delete-system-token now reads from stdin or a file, and docs/tests were updated accordingly.\n\nv1.2.2 | 2026-05-06T05:39:37.289Z | user\n\nAlign RAGFlow skill with v0.25.1-only routes and docs; remove stale 0.25.0 compatibility text; refresh tests and references.\n\nv1.2.0 | 2026-04-29T04:34:35.169Z | user\n\nAdd practical agent guide, minimal agent DSL examples, iteration runtime fixes, and agent chat response normalization\n\nv1.1.0 | 2026-04-28T09:18:28.892Z | user\n\nAdd embedded site access, preserve upload filenames, and refresh docs\n\nv1.0.0 | 2026-04-27T05:49:33.333Z | user\n\nInitial public release for RAGFlow v0.25.x\n\nArchive index:\n\nArchive v3.0.0: 17 files, 64254 bytes\n\nFiles: agents/openai.yaml (213b), lib/api.js (35159b), references/AGENT_GUIDE.md (12310b), references/API.md (21821b), references/COMMANDS.md (29980b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (1920b), references/TROUBLESHOOTING.md (7446b), scripts/ragflow.js (72173b), scripts/repro-delete-chunks.js (6832b), skill-card.md (2099b), SKILL.md (10216b), _meta.json (136b)\n\nFile v3.0.0:SKILL.md\n\n---\nname: skill-for-ragflow\ndescription: Operate RAGFlow v0.27.2 deployments through a bundled Node CLI for everyday knowledge-base setup, document ingestion, parsing, retrieval, chat assistants, agents, GraphRAG, connectors, models, and diagnostics. Use when a request explicitly involves a RAGFlow server, dataset, document pipeline, or RAGFlow agent.\nmetadata:\n  openclaw:\n    requires:\n      bins:\n        - node\n      env:\n        - RAGFLOW_URL\n        - RAGFLOW_API_KEY\n    primaryEnv: RAGFLOW_API_KEY\n    homepage: https://github.com/LunarCache/ragflow-skill\n---\n\n# RAGFlow Skill\n\nOperate common RAGFlow v0.27.2 workflows through `node {baseDir}/scripts/ragflow.js <command> [options]`. Prefer `--json` when parsing or chaining results. Prioritize daily operations over exhaustive API coverage.\n\nThis package targets v0.27.2 and accepts only current API parameters. Use `--knn-top-k` for retrieval and `--session` for chat; no deprecated aliases or legacy streaming mode are supported.\n\n## Requirements\n\n- Set `RAGFLOW_URL` and `RAGFLOW_API_KEY` in the environment or this skill's `.env`.\n- Use Node.js to run bundled scripts.\n- Run `system-health --json` after first-time setup to verify service reachability and dependencies. Run `system-version --json` to identify the deployment version. Use `list-datasets --page-size 1 --json` to verify API-key authentication.\n\n## Security Notes\n\n- **Use HTTPS in production.** Production deployments should use `https://` for `RAGFLOW_URL` to protect the API key in transit. Local development (`http://localhost`) is acceptable for testing.\n- **Use a dedicated, rotatable API key for automation.** RAGFlow v0.27.2 API keys are tenant-scoped rather than permission-scoped.\n- **Protect your API key.** Never share `RAGFLOW_API_KEY` in chat messages or commit it to version control. Use environment variables or the skill's `.env` file.\n\n## Quick Command Reference\n\n| Scenario | Commands |\n|----------|----------|\n| **Knowledge base setup** | `create-dataset`, `list-datasets`, `get-dataset`, `update-dataset`, `delete-datasets` |\n| **Document ingestion** | `upload-documents`, `ingest-documents`, `list-documents`, `get-document`, `update-document`, `delete-documents`, `download-document`, `preview-document`, `metadata-summary`, `update-metadata` |\n| **Parsing & chunking** | `start-parsing`, `stop-parsing`, `wait-parsing`, `list-chunks`, `get-chunk`, `add-chunk`, `update-chunk`, `delete-chunks`, `get-document-graph`, `delete-document-graph` |\n| **Direct retrieval** | `retrieve` |\n| **Chat assistant** | `create-chat`, `list-chats`, `get-chat`, `update-chat`, `patch-chat`, `delete-chats` |\n| **Chat sessions** | `create-session`, `list-sessions`, `get-session`, `update-session`, `delete-sessions`, `chat`, `chat-session` |\n| **Agent** | `create-agent`, `list-agents`, `get-agent`, `update-agent`, `delete-agents` |\n| **Agent Tags** | `list-agent-tags`, `update-agent-tags` |\n| **Agent sessions** | `create-agent-session`, `list-agent-sessions`, `delete-agent-sessions`, `agent-chat` |\n| **Connector** | `list-connectors`, `create-connector`, `get-connector`, `update-connector`, `delete-connector` |\n| **RAPTOR** | `run-raptor`, `trace-raptor` |\n| **GraphRAG** | `get-knowledge-graph`, `delete-knowledge-graph`, `run-graphrag`, `trace-graphrag` |\n| **Embedded website access** | `list-system-tokens`, `create-system-token`, `delete-system-token`, `embed-code`, `embed-info`, `embed-chat`, `embed-agent-chat` |\n| **Model discovery** | `list-models`, `list-added-models`, `list-default-models`, `set-default-model` |\n| **Model providers** | `list-providers`, `get-provider`, `add-provider`, `delete-provider`, `list-provider-models`, `list-provider-instances`, `get-provider-instance`, `create-provider-instance`, `delete-provider-instances`, `verify-provider`, `list-instance-models`, `add-instance-model`, `set-model-status` |\n| **System** | `system-version`, `system-health`, `get-log-levels`, `set-log-level` |\n\n## Common Workflows\n\n### Full RAG pipeline (upload -> parse -> retrieve)\n\n1. `create-dataset --name \"My KB\" --chunk-method naive`\n2. `upload-documents --dataset <id> --files ./doc1.pdf ./doc2.txt`\n3. `start-parsing --dataset <id> --doc-ids <doc_id1> <doc_id2>`\n4. `wait-parsing --dataset <id> --doc-ids <doc_id1> <doc_id2>`\n5. `retrieve --question \"What is X?\" --datasets <id>`\n\n### Chat assistant with sessions\n\n1. `create-chat --name \"Q&A\" --datasets <id> --llm-id qwen-turbo@Tongyi-Qianwen`\n2. `create-session --chat <chat_id>`\n3. `chat-session --chat <chat_id> --session <session_id> --question \"Hello\"`\n\n### Agent workflow\n\n1. `create-agent --title \"Assistant\" --dsl @agent_dsl.json`\n2. `create-agent-session --agent <agent_id>`\n3. `agent-chat --agent <agent_id> --session <session_id> --question \"Hello\"`\n\n`agent-chat` streams by default. Use `--stream false` for one final JSON response.\n\n### Connector workflow\n\n1. `create-connector --config @connector.json`\n2. `list-connectors`\n3. `get-connector --id <id>`\n\n### Model provider workflow (v0.27.2)\n\n1. `list-providers --available` to see configurable providers\n2. `add-provider --name <provider>`\n3. Set `RAGFLOW_PROVIDER_API_KEY`, then run `create-provider-instance --name <provider> --instance <name>` (credentials live on an instance; a provider can have several)\n4. `add-instance-model --name <provider> --instance <name> --model-name <model> --model-type chat`\n5. `set-default-model --model-type chat --model-provider <provider> --model-instance <name> --model-name <model>`\n\nUse `verify-provider --name <provider>` with `RAGFLOW_PROVIDER_API_KEY` set, or pass `--api-key-file <path>`, to test a key without persisting an instance.\n\n### Indexing and retrieval\n\nRun `run-raptor --dataset <id>` then `trace-raptor --dataset <id>`, or the equivalent `run-graphrag` / `trace-graphrag` commands. Retrieval uses `--knn-top-k`; when paginating, set `--rerank-candidates-count` to cover `--page × --top-n`. Read the command reference for server defaults and filtering.\n\n### Embedded website access\n\n1. `embed-code --chat <chat_id> --type fullscreen` or `embed-code --agent <agent_id> --type widget`\n2. `embed-info --chat <chat_id>` or `embed-info --agent <agent_id>`\n3. `embed-chat --chat <chat_id> --question \"Hello\"` or `embed-agent-chat --agent <agent_id> --question \"Hello\"`\n\n`embed-chat` automatically creates the embedded chatbot session when `--session` is omitted. RAGFlow's shared-site route only creates a session and returns the prologue on the first no-session request, so the CLI bootstraps `session_id` first and then sends the real question.\n\n## Workflow Decision Guide\n\nThe first step in any RAGFlow operation is resolving the target resource ID. After that, choose the right path:\n\n1. **Authoring or debugging a custom agent DSL?** -> Read [references/AGENT_GUIDE.md](references/AGENT_GUIDE.md) - it is a self-contained guide to the current RAGFlow agent DSL schema and includes minimal examples.\n2. **Need CLI syntax or option details?** -> Read [references/COMMANDS.md](references/COMMANDS.md) - it's organized by workflow scenario with full option tables.\n3. **Editing client code or checking request/response shapes?** -> Read [references/API.md](references/API.md) - it has examples for supported `RagflowClient` workflows.\n4. **A command failed?** -> Read [references/TROUBLESHOOTING.md](references/TROUBLESHOOTING.md) - common errors with causes and fixes.\n5. **Formatting output for the user?** -> Read [references/REFERENCE.md](references/REFERENCE.md) - consistent response templates and status labels.\n\n## Key Constraints\n\n- **Confirm destructive scope.** Verify that the user authorized the exact target before deletion, metadata removal or dataset-wide metadata changes, or ingestion that purges existing tasks/chunks. Then pass `--confirm-destructive` for that invocation; the CLI otherwise refuses the request. Existing explicit authorization and cleanup of temporary resources from the requested workflow do not require a repeated question. Never add the flag automatically in response to a refusal.\n- **Choose the ingestion path first.** For built-in chunking, upload documents, adjust their parser configuration when needed, then run `start-parsing`. For ingestion-pipeline datasets, use `ingest-documents` instead.\n- **Preserve source filenames.** When an attachment is stored under a temporary or task-generated path, upload it as `--files <original-name>=<path>` so RAGFlow retains the user-facing name.\n- **Resolve complete, stable inputs.** Discover resource IDs with the corresponding `list-*` or `get-*` command, and paginate beyond RAGFlow's 100-item list limit. Use the `identifier` from `list-models` (`<model>@<instance>@<provider>`, or `<model>@<provider>` for the default instance) for `--embedding-model` and `--llm-id`; treat numeric model row IDs as display data only.\n- **Preserve session-history intent.** Let `chat-session` append the latest user message by default. Use `--pass-all-history` only when replacing stored history.\n- **Protect operational secrets.** Keep `RAGFLOW_API_KEY`, provider keys, system tokens, beta values, and embed URLs containing `auth=` out of user-facing output. Supply provider credentials through `RAGFLOW_PROVIDER_API_KEY` or `--api-key-file`; reveal secret material only when the user explicitly requests copy-paste output.\n- **Use the correct public embed origin.** Pass `--origin` when the browser-facing RAGFlow URL differs from `RAGFLOW_URL`. Let the CLI reuse or create a beta token and bootstrap the embedded chat session.\n- **Start Agent DSL work from the guide.** Read [references/AGENT_GUIDE.md](references/AGENT_GUIDE.md) before authoring or debugging agents, and adapt its minimal examples instead of reconstructing the canvas schema from memory.\n\n## Output Format\n\nUse raw `--json` internally, then summarize the operational result. Preserve the server's parsing labels (`UNSTART`, `RUNNING`, `CANCEL`, `DONE`, `FAIL`) and similarity scores. Redact API keys, system tokens, beta values, and `auth=` query values unless the user explicitly requests copy-paste secret material. Read [references/REFERENCE.md](references/REFERENCE.md) only when a result needs a domain-specific response template.\n\nFile v3.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn71t9qydjdg0w265b8n777sp585m9xj\",\n  \"slug\": \"skill-for-ragflow\",\n  \"version\": \"3.0.0\",\n  \"publishedAt\": 1790303914249\n}\n\nFile v3.0.0:references/AGENT_GUIDE.md\n\n# RAGFlow Custom Agent Guide\n\nRead this file only when you need to author, debug, or review a RAGFlow Agent/Canvas DSL. For CLI syntax, read [COMMANDS.md](COMMANDS.md). For SDK request and response shapes, read [API.md](API.md). For failures and recovery steps, read [TROUBLESHOOTING.md](TROUBLESHOOTING.md).\n\nThis guide distills the current RAGFlow v0.27.2 agent behavior into practical schema rules, minimal examples, and failure patterns you can use directly.\n\n## Contents\n\n- [Quick choice](#quick-choice)\n- [Shortest path](#shortest-path)\n- [Current schema checklist](#current-schema-checklist)\n- [Components and graph must agree](#components-and-graph-must-agree)\n- [Variable rules](#variable-rules)\n- [Customize by node type](#customize-by-node-type)\n- [Runtime conclusions](#runtime-conclusions)\n- [Minimal example index](#minimal-example-index)\n- [Common failures](#common-failures)\n\n## Quick choice\n\n| Goal | Read first | Start from |\n|---|---|---|\n| Build the smallest conversational agent | [Shortest path](#shortest-path) | `references/examples/agents/01-conversational-message.json` |\n| Add knowledge-base retrieval | [Customize by node type](#customize-by-node-type) for `Retrieval` and `Agent` | `references/examples/agents/02-retrieval-message.json` or `03-tool-agent.json` |\n| Build a tool-using LLM agent | [Customize by node type](#customize-by-node-type) for `Agent` | `references/examples/agents/03-tool-agent.json` |\n| Build a loop or batch-processing agent | [Customize by node type](#customize-by-node-type) for `Iteration / IterationItem` | `references/examples/agents/04-iteration-agent.json` |\n| Build a webhook agent | [Customize by node type](#customize-by-node-type) for `Webhook` | `references/examples/agents/05-webhook-message.json` |\n| Debug `KeyError('path')`, broken variable resolution, or skipped nodes | [Current schema checklist](#current-schema-checklist) and [Common failures](#common-failures) | Compare against your DSL |\n\n## Shortest path\n\nDo not start from an empty JSON object.\n\n1. Pick the closest file from `references/examples/agents/`.\n2. Replace only deployment-specific values such as `llm_id`, `kb_ids`, tool credentials, and prompt text.\n3. Keep the current runtime fields intact: `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`.\n4. Create the agent, look it up by title, create a session, and send a question.\n\n```bash\nnode {baseDir}/scripts/ragflow.js create-agent \\\n  --title \"My Agent\" \\\n  --dsl @references/examples/agents/01-conversational-message.json \\\n  --json\n\nnode {baseDir}/scripts/ragflow.js list-agents --name \"My Agent\" --json\nnode {baseDir}/scripts/ragflow.js create-agent-session --agent <agent_id> --json\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\" --json\n```\n\n`create-agent` currently returns `true` on success, not the new agent id.\n\n## Current schema checklist\n\nWhen you hand-author a DSL, keep this checklist:\n\n- Top level includes `components`, `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`\n- `components` is the runtime structure and `graph` is the canvas structure; node ids must line up across both\n- Every `graph.nodes[]` entry includes `data.name`\n- `globals` explicitly keeps the system variables\n- Every referenced `component_id` actually exists\n- Loop flows define both `Iteration` and `IterationItem`\n- Tool-enabled agents place tools under `Agent.params.tools`\n\nRecommended skeleton:\n\n```json\n{\n  \"components\": {},\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [],\n    \"edges\": []\n  }\n}\n```\n\nAdditional constraints:\n\n- Keep `sys.date` even though runtime refreshes it\n- `env.*` values come from top-level `variables`\n- `component_id@output_name` values come from node outputs\n- Prefer the current schema instead of relying on server-side migration from old DSL formats\n\n## Components and graph must agree\n\nRAGFlow agent DSL is not just an execution graph and not just a canvas export. `components` and `graph` must both be valid and must describe the same flow.\n\n### `components`\n\nEvery component should at least look like this:\n\n```json\n{\n  \"begin\": {\n    \"obj\": {\n      \"component_name\": \"Begin\",\n      \"params\": {}\n    },\n    \"downstream\": [\"message:0\"],\n    \"upstream\": []\n  }\n}\n```\n\nKey fields:\n\n- `obj.component_name`: runtime component type\n- `obj.params`: runtime parameters\n- `downstream`: successor component ids\n- `upstream`: predecessor component ids\n- `parent_id`: needed only for nested nodes such as `IterationItem`\n\n### `graph.nodes`\n\nEvery graph node should at least keep these fields:\n\n```json\n{\n  \"id\": \"begin\",\n  \"type\": \"beginNode\",\n  \"position\": { \"x\": 50, \"y\": 200 },\n  \"data\": {\n    \"label\": \"Begin\",\n    \"name\": \"begin\",\n    \"form\": {\n      \"mode\": \"conversational\",\n      \"prologue\": \"Hi! I'm your assistant.\"\n    }\n  }\n}\n```\n\nKey constraints:\n\n- `graph.nodes[].id` matches the `components` key\n- `graph.nodes[].data.name` is required\n- `graph.nodes[].data.form` should stay aligned with `obj.params`\n\n### `graph.edges`\n\nEach edge `source` and `target` must reference real component ids. Updating only `components.downstream` or only `graph.edges` leaves the runtime and canvas out of sync.\n\n## Variable rules\n\nRuntime variable resolution mainly supports three classes:\n\n- System variables: `{sys.query}`, `{sys.user_id}`, `{sys.history}`\n- Environment variables: `{env.foo}`\n- Component outputs: `{retrieval:0@formalized_content}`, `{begin@body.message}`\n\nRules:\n\n- Variables without `@` are read from `globals`\n- Variables with `@` must use `component_id@output_name`\n- Dot-path access is supported, for example `{begin@body.message}` or `{agent:0@structured.items.0.title}`\n\nMost variable failures come from ids, output names, or top-level fields not lining up.\n\n## Customize by node type\n\n### Begin\n\n`Begin.params.mode` currently supports:\n\n- `conversational`\n- `task`\n- `Webhook`\n\n`Webhook` is not an alias for ordinary chat mode. It triggers a separate webhook route and request-validation path.\n\n### Message\n\n`Message` most often emits the final answer:\n\n```json\n{\n  \"content\": [\n    \"{agent:0@content}\"\n  ]\n}\n```\n\n`content` is an array. Runtime selects one template at random, and templates can contain variable references.\n\n### Retrieval\n\n`Retrieval` can be either a canvas node or a tool definition inside `Agent.params.tools`. Common inputs are:\n\n- `query`\n- `kb_ids`\n- `similarity_threshold`\n- `top_n`\n- `top_k`\n\nIf you want an explicit retrieval stage on the canvas, start from `02-retrieval-message.json`. If you want retrieval as an LLM tool, start from `03-tool-agent.json`.\nAs of v0.27.0, metadata filters are correctly reused across canvas executions even when node state is modified, fixing an issue where filters could be lost during iterative debugging.\n\n### Agent\n\n`Agent` is the tool-capable LLM node. In the current structure, tools live under `Agent.params.tools`:\n\n```json\n{\n  \"tools\": [\n    {\n      \"component_name\": \"Retrieval\",\n      \"id\": \"Retrieval:tool0\",\n      \"name\": \"Retrieval\",\n      \"params\": {}\n    }\n  ]\n}\n```\n\nDo not model tools here as separate top-level `Tool` nodes. For this skill, prefer the embedded structure shown in `03-tool-agent.json`.\n`Agent` nodes can emit structured JSON output directly into the `structured` field when a JSON schema is provided, allowing downstream nodes to access fields without manual string parsing.\n\n### Iteration / IterationItem\n\nLoops require at least:\n\n- one `Iteration`\n- one `IterationItem`\n- `IterationItem.parent_id` pointing to its `Iteration`\n- `Iteration.params.items_ref` pointing to the collection being iterated\n\nTwo practical constraints matter here:\n\n- `items_ref` must resolve to a real list at runtime\n- if the upstream value comes from an `Agent`, do not make the agent emit a top-level array schema directly; use an object schema such as `{\"items\": [\"...\"]}` and point `items_ref` at `agent:0@structured.items`\n\n`04-iteration-agent.json` uses that pattern because it works against the current backend implementation.\n\n### Webhook\n\nWhen `Begin.mode = \"Webhook\"`, the server reads these extra fields:\n\n### Browser\n\n`Browser` is a component type that enables AI-driven browser automation within agent workflows. It allows agents to navigate web pages, extract content, and interact with browser elements programmatically. Use it when the agent needs to access live web data or perform web-based tasks as part of its workflow.\n\nWhen `Begin.mode = \"Webhook\"`, the server reads these extra fields:\n\n- `methods`\n- `content_types`\n- `schema`\n- `security`\n- `execution_mode`\n- `response`\n\n`schema` should follow the current exported JSON-schema-style object:\n\n```json\n{\n  \"body\": {\n    \"type\": \"object\",\n    \"required\": [\"message\"],\n    \"properties\": {\n      \"message\": { \"type\": \"string\" }\n    }\n  }\n}\n```\n\nUse `05-webhook-message.json` as the minimal reference.\n\n## Runtime conclusions\n\nRead this section only when you need to explain why a DSL can be created but still fails at session creation or runtime.\n\n### Creation\n\n`create-agent` calls `POST /api/v1/agents`. The server normalizes the DSL, which means:\n\n- `--dsl` can be inline JSON\n- `--dsl` can also be `@agent.json`\n- old component names and old node types may be migrated, but migration should not be treated as the target schema\n\n### Session\n\n`create-agent-session` creates a new `Canvas` from the current agent DSL, resets runtime state, and stores the current DSL in the session. A session keeps more than chat messages; it also keeps runtime DSL state.\n\n### Run\n\n`agent-chat` calls `POST /api/v1/agents/chat/completions` with `agent_id` in the body. Runtime updates:\n\n- `sys.query`\n- `history`\n- `sys.history`\n- `sys.conversation_turns`\n- `retrieval`\n\nThat is why removing these runtime-looking top-level fields can still let agent creation succeed while session creation or execution later fails.\n\n## Minimal example index\n\nAll examples live in `references/examples/agents/` and can be used directly with `--dsl @...`:\n\n| File | Best for | Usually replace |\n|---|---|---|\n| `01-conversational-message.json` | Smallest conversational agent, `Begin -> Message` | `prologue`, output template |\n| `02-retrieval-message.json` | Explicit retrieval chain, `Begin -> Retrieval -> Message` | `kb_ids`, retrieval thresholds, output template |\n| `03-tool-agent.json` | Tool-using LLM agent, `Begin -> Agent -> Message` | `llm_id`, `tools`, prompt |\n| `04-iteration-agent.json` | Loop or batch-processing agent | `items_ref`, loop-body prompt, aggregate output |\n| `05-webhook-message.json` | Webhook agent, `Begin(Webhook) -> Message` | `schema`, `security`, response definition |\n\nThese examples are structurally minimal, not production-minimal. Replace `llm_id`, `kb_ids`, API keys, webhook security settings, and any other deployment-specific values with real ones from your environment.\n\n## Common failures\n\n| Problem | Cause |\n|---|---|\n| `KeyError('path')` or session creation failure | Top-level runtime fields are incomplete |\n| Agent creates successfully but runtime cannot resolve variables | `graph.nodes[].id`, `components` keys, and variable references do not line up |\n| Logs or debugging output lose component names | `graph.nodes[].data.name` is missing |\n| Agent appears to have tools but never calls them | Tools were not written into `Agent.params.tools` |\n| Webhook agent creates successfully but endpoint behavior is broken | `Begin.mode`, `schema`, `security`, or `response` does not match the current implementation |\n| Iteration agent creates successfully but crashes at execution time | `items_ref` resolved to `None` or a non-list, often because the upstream `Agent` did not produce a real `structured.items` array |\n| Old DSL imports but behaves strangely | The server migrated it, but the final structure was not rewritten to the current schema |\n### v0.27.2 validation notes\n\nInteger DSL parameters must be JSON integers: fractional values such as `1.5` and booleans are rejected for positive/nonnegative-integer fields. Template references accept `{node@output}` or `{{node@output}}`; keep braces balanced.\n\nFile v3.0.0:references/API.md\n\n# Programmatic API and Configuration\n\n## Table of Contents\n\n- [Setup](#setup)\n- [Dataset](#dataset)\n- [Document](#document)\n- [Document Download](#document-download)\n- [Parsing](#parsing)\n- [Chunk](#chunk)\n- [Retrieval](#retrieval)\n- [Metadata](#metadata)\n- [Connector](#connector)\n- [RAPTOR](#raptor)\n- [GraphRAG](#graphrag)\n- [Chat Assistant](#chat-assistant)\n- [Session](#session)\n- [Chat Conversation](#chat-conversation)\n- [Agent](#agent)\n- [Agent Tags](#agent-tags)\n- [Agent Session](#agent-session)\n- [Agent Chat](#agent-chat)\n- [Embedded Website Access](#embedded-website-access)\n- [LLM Models](#llm-models)\n- [System](#system)\n- [Utility](#utility)\n- [Configuration](#configuration)\n\n## Setup\n\n```javascript\nconst { createClient } = require(\"{baseDir}/lib/api.js\");\nconst client = createClient();\n```\n\n`createClient()` reads `RAGFLOW_URL` and `RAGFLOW_API_KEY` from the environment and then fills missing values from the bundled `.env` file. Existing environment variables take precedence. See [Configuration](#configuration) below.\n\nDestructive requests fail with `CONFIRMATION_REQUIRED` before network access by default. After verifying authorization and target scope, create a dedicated client with `const destructiveClient = createClient({ allowDestructive: true });` for deletion, metadata removal or unscoped metadata updates, and ingestion with `delete: true`. Use that client for the deletion examples below; ordinary clients remain suitable for reads and scoped updates.\n\n## Dataset\n\n```javascript\n// List datasets (supports pagination: page, page_size, id, name)\nconst datasets = await client.listDatasets({ page: 1, page_size: 10 });\n\n// Get a single dataset by ID (enriched with total_size and connectors)\nconst dataset = await client.getDataset(\"<dataset_id>\");\n// Returns: { id: \"...\", name: \"...\", total_size: 1024, connectors: [...], ... }\n\n// Create a dataset\nconst dataset = await client.createDataset({\n  name: \"Tech Docs\",\n  chunk_method: \"naive\",\n});\n\n// Update a dataset\nawait client.updateDataset(\"<dataset_id>\", { name: \"New Name\" });\n\n// Delete datasets by IDs\nawait destructiveClient.deleteDatasets([\"<id1>\", \"<id2>\"]);\n```\n\n## Document\n\n```javascript\n// Upload documents\nawait client.uploadDocuments(\"<dataset_id>\", [\"./report.pdf\", \"./notes.txt\"]);\n\n// Override display names when paths are temporary/task IDs\nawait client.uploadDocuments(\"<dataset_id>\", [\n  { path: \"./tmp/task-output\", name: \"report.pdf\" },\n]);\n\n// List documents (supports page, page_size, id, name, orderby, desc, keywords, suffix, types, run, metadata, metadata_condition, return_empty_metadata)\nconst docs = await client.listDocuments(\"<dataset_id>\");\n\n// Get a single document by ID\nconst doc = await client.getDocument(\"<dataset_id>\", \"<doc_id>\");\n\n// Update a document\nawait client.updateDocument(\"<dataset_id>\", \"<doc_id>\", {\n  name: \"Renamed\",\n  parser_config: { pages: [[1, 2]] },\n  chunk_method: \"knowledge_graph\",\n  enabled: 1,\n  meta_fields: { author: \"Alice\" },\n});\n\n// Delete documents by IDs\nawait destructiveClient.deleteDocuments(\"<dataset_id>\", [\"<doc_id1>\", \"<doc_id2>\"]);\n```\n\nRAGFlow v0.27.2 defines document updates as `PATCH /api/v1/datasets/{dataset_id}/documents/{document_id}`. `updateDocument()` sends that request directly.\n\nYou can also filter documents by metadata:\n\n```javascript\nconst docs = await client.listDocuments(\"<dataset_id>\", {\n  metadata_condition: JSON.stringify({\n    logic: \"and\",\n    conditions: [{ name: \"status\", comparison_operator: \"=\", value: \"published\" }],\n  }),\n});\n```\n\nYou can also summarize metadata across documents:\n\n```javascript\nconst summary = await client.metadataSummary(\"<dataset_id>\", [\"<doc_id1>\", \"<doc_id2>\"]);\n// Returns: { summary: [...] }\n```\n\n## Document Download\n\n```javascript\n// Download via dataset\nconst doc = await client.downloadDocument(datasetId, documentId);\n\n// Download by document ID\nconst doc = await client.downloadDocumentById(documentId);\n\n// Preview a document inline (v0.27.2)\nconst preview = await client.previewDocument(documentId);\n```\n\nDownloads/previews are normalized from binary HTTP responses into `{ content, encoding: \"base64\", name, content_type, size }`. Decode with `Buffer.from(doc.content, \"base64\")`; `content` is not plain text or a remote URL. JSON API errors and HTTP failures still reject the request.\n\n## Parsing\n\n```javascript\n// Start parsing (returns immediately)\nawait client.startParsing(\"<dataset_id>\", [\"<doc_id1>\"]);\n\n// Stop parsing\nawait client.stopParsing(\"<dataset_id>\", [\"<doc_id1>\"]);\n\n// Start/rerun ingestion for ingestion-pipeline datasets\nawait client.ingestDocuments([\"<doc_id1>\"], { run: \"1\", delete: true });\n\n// Cancel ingestion for ingestion-pipeline datasets\nawait client.ingestDocuments([\"<doc_id1>\"], { run: \"2\" });\n\n// Wait for parsing to complete (polls until DONE or FAIL)\n// Documents stuck in CANCEL keep polling until timeout.\nconst results = await client.waitForParsing(\"<dataset_id>\", [\"<doc_id1>\"], {\n  interval: 3000,   // poll interval in ms (default: 3000)\n  maxWait: 120000,  // max wait in ms (default: 120000)\n});\n```\n\n## Chunk\n\n```javascript\n// List chunks (supports pagination: page, page_size, keywords)\nconst chunks = await client.listChunks(\"<dataset_id>\", \"<doc_id>\");\n\n// Exact chunk lookup by ID\nconst chunk = await client.getChunk(\"<dataset_id>\", \"<doc_id>\", \"<chunk_id>\");\n\n// Add a chunk\nawait client.addChunk(\"<dataset_id>\", \"<doc_id>\", {\n  content: \"Custom chunk text\",\n  important_keywords: [\"keyword1\", \"keyword2\"],\n});\n\n// Update a chunk\nawait client.updateChunk(\"<dataset_id>\", \"<doc_id>\", \"<chunk_id>\", {\n  content: \"Updated content\",\n  important_keywords: [\"new_keyword\"],\n});\n\n// Delete chunks by IDs\nawait destructiveClient.deleteChunks(\"<dataset_id>\", \"<doc_id>\", [\"<chunk_id1>\"]);\n\n// Inspect or delete the document structure graph\nconst graph = await client.getDocumentStructureGraph(\"<dataset_id>\", \"<doc_id>\");\nawait destructiveClient.deleteDocumentStructureGraph(\"<dataset_id>\", \"<doc_id>\");\n```\n\n`updateChunk()` uses `PATCH /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks/{chunk_id}`. `ingestDocuments()` is for ingestion-pipeline datasets; use `startParsing()`/`stopParsing()` for the built-in chunking pipeline.\n\n`deleteChunks()` retries the transient `rm_chunk deleted chunks 0, expect N` response only after `getChunk()` confirms the target chunk still exists. This distinguishes document-store refresh delay from a genuinely missing chunk. Override with:\n\n```javascript\nawait destructiveClient.deleteChunks(\"<dataset_id>\", \"<doc_id>\", [\"<chunk_id1>\"], {\n  maxRetries: 0,\n  retryDelay: 1000,\n});\n```\n\nWhen the CLI is run with `--json`, `delete-chunks` wraps the server result with diagnostic fields that pipelines can consume directly:\n\n```json\n{\n  \"result\": {},\n  \"requested_chunk_ids\": [\"<chunk_id1>\"],\n  \"existing_chunk_ids\": [\"<chunk_id1>\"],\n  \"missing_chunk_ids\": [],\n  \"visibility_checked\": true,\n  \"retry_count\": 1,\n  \"retries\": [\n    {\n      \"attempt\": 0,\n      \"next_attempt\": 2,\n      \"max_retries\": 3,\n      \"existing_chunk_ids\": [\"<chunk_id1>\"],\n      \"missing_chunk_ids\": []\n    }\n  ]\n}\n```\n\nOn a final delete visibility failure, the CLI exits non-zero and emits JSON with `error`, `requested_chunk_ids`, `existing_chunk_ids`, `missing_chunk_ids`, `retry_count`, `retries`, and `delete_chunk_diagnostics`.\n\nAll CLI command failures in `--json` mode use the same top-level error envelope:\n\n```json\n{\n  \"error\": {\n    \"message\": \"API Error: Unauthorized\",\n    \"raw_message\": \"Unauthorized\",\n    \"code\": 401,\n    \"status\": 401,\n    \"command\": \"list-models\"\n  }\n}\n```\n\nCommand-specific diagnostics, such as delete chunk visibility checks, are added as extra top-level fields alongside `error`.\n\n## Retrieval\n\n```javascript\nconst results = await client.retrieve({\n  question: \"What is deep learning?\",\n  dataset_ids: [\"<dataset_id>\"],\n  similarity_threshold: 0.3,\n  page_size: 5,\n  knn_top_k: 1024,\n  knn_num_candidates: 2048,\n  rerank_candidates_count: 64,\n  highlight: true,\n  include_knowledge_compilation: false,\n  vector_similarity_weight: 0.7,\n  keyword: true,\n  use_kg: false,\n  rerank_id: \"<rerank_model_id>\",\n});\n```\n\n`retrieve()` forwards the payload unchanged. Prefer `knn_top_k` over the deprecated `top_k`; `knn_num_candidates` must be at least `knn_top_k`. Set `rerank_candidates_count >= page * page_size` (defaults: 64, 1, 30). `document_ids` and `metadata_condition` filters intersect. `include_knowledge_compilation: false` excludes compiled chunks. The response is `{ chunks, total, doc_aggs }`.\n\n## Metadata\n\n```javascript\n// Batch-update or delete metadata for selected documents.\nawait client.updateMetadata(\"<dataset_id>\", {\n  selector: { document_ids: [\"<doc_id>\"] },\n  updates: [{ key: \"status\", value: \"reviewed\" }],\n});\n```\n\n## Connector\n\nConnectors are tenant-scoped (not dataset-scoped). The client calls the tenant-level routes.\n\n```javascript\n// List connectors (tenant scope)\nconst connectors = await client.listConnectors();\n\n// Create connector\nconst connector = await client.createConnector({\n  name: \"Documentation sitemap\",\n  source: \"sitemap\",\n  config: { sitemap_url: \"https://example.com/sitemap.xml\" }\n});\n\n// Get, update, delete connector\nconst conn = await client.getConnector(connectorId);\nawait client.updateConnector(connectorId, { refresh_freq: 10 });\nawait destructiveClient.deleteConnector(connectorId);\n```\n\n## RAPTOR\n\n```javascript\n// Start RAPTOR processing\nconst task = await client.runRaptor(datasetId);\n\n// Check progress\nconst progress = await client.traceRaptor(datasetId);\n```\n\n## GraphRAG\n\n```javascript\nconst graph = await client.getKnowledgeGraph(datasetId);\nawait client.runGraphRag(datasetId);\nconst progress = await client.traceGraphRag(datasetId);\nawait destructiveClient.deleteKnowledgeGraph(datasetId);\n```\n\n## Chat Assistant\n\n```javascript\n// List chat assistants (supports pagination)\nconst chats = await client.listChatAssistants({ page: 1, page_size: 10 });\n\n// Get a single chat assistant by ID\nconst chat = await client.getChatAssistant(\"<chat_id>\");\n\n// Create a chat assistant\nconst chat = await client.createChatAssistant({\n  name: \"Tech Q&A\",\n  dataset_ids: [\"<dataset_id>\"],\n  llm_id: \"qwen-turbo@Tongyi-Qianwen\",\n  prompt_config: { system: \"You are a helpful assistant.\" },\n  similarity_threshold: 0.3,\n  top_n: 5,\n});\n\n// Update a chat assistant\nawait client.updateChatAssistant(\"<chat_id>\", { name: \"New Name\" });\n\n// Patch a chat assistant\nawait client.patchChatAssistant(\"<chat_id>\", { prompt_config: { system: \"Use the dataset\" } });\n\n// Delete chat assistants by IDs\nawait destructiveClient.deleteChatAssistants([\"<chat_id1>\", \"<chat_id2>\"]);\n```\n\n## Session\n\n```javascript\n// List sessions for a chat assistant\nconst sessions = await client.listSessions(\"<chat_id>\", { page: 1 });\n\n// Create a session\nconst session = await client.createSession(\"<chat_id>\", { name: \"Q&A Session\" });\n\n// Inspect or rename a session\nconst current = await client.getSession(\"<chat_id>\", \"<session_id>\");\nawait client.updateSession(\"<chat_id>\", \"<session_id>\", { name: \"Reviewed Q&A\" });\n\n// Delete sessions by IDs\nawait destructiveClient.deleteSessions(\"<chat_id>\", [\"<session_id1>\"]);\n```\n\n## Chat Conversation\n\n```javascript\n// Chat with an assistant (streaming SSE, returns final answer + references)\nconst answer = await client.chat(\"<chat_id>\", \"<session_id>\", \"What is RAG?\");\n// Returns: { answer: \"...\", reference: { ... } }\n\n// Chat with a session (messages payload)\nconst sessionAnswer = await client.chatSession(\"<chat_id>\", \"<session_id>\", {\n  question: \"Summarize the policy.\",\n});\n\n// Convenience form: the last user message becomes `question`\nconst sessionAnswerFromMessages = await client.chatSession(\"<chat_id>\", \"<session_id>\", {\n  messages: [\n    { role: \"system\", content: \"Follow the dataset.\" },\n    { role: \"user\", content: \"Summarize the policy.\" },\n  ],\n});\n```\n\n`chatSession()` uses `POST /api/v1/chat/completions` with `chat_id` and `session_id` in the JSON body. Use `session_id` for session identity. By default, only the latest user message is appended to the stored history. Set `pass_all_history_messages: true` to replace the entire history with the submitted messages array. The client only supports the current streaming format.\n\n## Agent\n\n```javascript\n// List agents (supports pagination)\nconst agents = await client.listAgents({ page: 1 });\n\n// Get a single agent by ID\nconst agent = await client.getAgent(\"<agent_id>\");\n\n// Create an agent (use the current canvas DSL schema from AGENT_GUIDE.md)\nconst agent = await client.createAgent({ title: \"My Agent\", dsl: { ... } });\n\n// Update an agent\nawait client.updateAgent(\"<agent_id>\", { title: \"Updated Agent\" });\n\n// Delete agents by IDs\nawait destructiveClient.deleteAgents([\"<agent_id1>\"]);\n```\n\n`createAgent()` and `updateAgent()` forward the DSL directly to RAGFlow, where the server normalizes it through the canvas DSL normalization layer. In practice, hand-authored DSL should include `components`, `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`, and every component-backed graph node should include `data.name`. See [AGENT_GUIDE.md](AGENT_GUIDE.md) for the current schema and minimal examples.\n\n## Agent Tags\n\n```javascript\n// List all agent tags\nconst tags = await client.listAgentTags();\n\n// Update agent tags\nawait client.updateAgentTags(agentId, [\"ml\", \"rag\"]);\n```\n\n## Agent Session\n\n```javascript\n// List agent sessions\nconst sessions = await client.listAgentSessions(\"<agent_id>\", { page: 1 });\n\n// Create an agent session\nconst session = await client.createAgentSession(\"<agent_id>\", { name: \"Session 1\" });\n\n// Delete agent sessions by IDs\nawait destructiveClient.deleteAgentSessions(\"<agent_id>\", [\"<session_id1>\"]);\n```\n\n## Agent Chat\n\n```javascript\n// Chat with an agent (streaming SSE, returns final answer + references)\nconst answer = await client.agentChat(\"<agent_id>\", \"<session_id>\", \"Analyze the data\");\n// Returns: { answer: \"...\", reference: { ... } }\n\n// Ask for a final JSON response instead of SSE\nconst finalAnswer = await client.agentChat(\"<agent_id>\", \"<session_id>\", \"Analyze the data\", {\n  stream: false,\n});\n// Returns: { answer: \"...\", reference: { ... }, session_id: \"...\", id: \"...\" }\n```\n\nWhen `stream: false` is used, `agentChat()` still normalizes current `workflow_finished` or `done` JSON envelopes into the same final answer shape used by the streaming path.\n`agentChat()` uses `POST /api/v1/agents/chat/completions` with `agent_id` in the JSON body.\n\n## Embedded Website Access\n\n```javascript\n// Reuse an existing system token with beta, or create one if needed\nconst embedToken = await client.ensureEmbedToken();\n\n// Token management\nconst tokens = await client.listSystemTokens();\nconst newToken = await client.createSystemToken();\nawait destructiveClient.deleteSystemToken(newToken.token);\n\n// Chat assistant shared-site metadata and completion\nconst chatInfo = await client.getEmbeddedChatInfo(\"<chat_id>\", embedToken.beta);\nconst embeddedSessionId = await client.ensureEmbeddedChatSession(\"<chat_id>\", embedToken.beta, {\n  quote: true,\n});\nconst chatAnswer = await client.embeddedChat(\"<chat_id>\", embedToken.beta, {\n  question: \"Hello\",\n  session_id: embeddedSessionId,\n  quote: true,\n  stream: false,\n});\n\n// Agent shared-site inputs and completion\nconst agentInputs = await client.getEmbeddedAgentInputs(\"<agent_id>\", embedToken.beta);\nconst agentAnswer = await client.embeddedAgentChat(\"<agent_id>\", embedToken.beta, {\n  id: \"<agent_id>\",\n  query: \"Hello\",\n  inputs: {},\n  stream: false,\n});\n```\n\nEmbedded calls use RAGFlow's shared-site routes under `/api/v1/chatbots/*` and `/api/v1/agentbots/*`. They authenticate with the token `beta` value, not the normal API token.\n\nFor chatbot completions, RAGFlow creates the embedded session on the first no-session request and returns the assistant prologue instead of answering the user's question. Use `ensureEmbeddedChatSession()` first, or include a known `session_id`, before calling `embeddedChat()` with the real question. The CLI `embed-chat` command performs this bootstrap automatically when `--session` is omitted.\n\n## LLM Models\n\n```javascript\n// List available models (v0.27.2 flat tenant model catalog)\nconst models = await client.listModels({ type: \"chat\" });\n// GET /api/v1/models -> [{ name, model_type, provider_name, model_id, ... }]\n// Client returns the server catalog array; CLI list-models groups it as { groups, total }.\n```\n\nRAGFlow v0.27.2 exposes model discovery at `/api/v1/models` (replacing the legacy `/v1/llm/my_llms`, which was removed in v0.27.0). Authentication uses `RAGFLOW_API_KEY`. There is no legacy endpoint fallback; `listModelsLegacy()` has been removed.\n\nUse `identifier` from CLI `list-models`, including `<model>@<instance>@<provider>` for a named instance. For the default instance, use model names plus provider suffixes when creating resources, for example `qwen-turbo@Tongyi-Qianwen` for `llm_id` and `text-embedding-v4@Tongyi-Qianwen` for `embedding_model`. Some deployments return numeric `id` fields; those are server row IDs and should not be sent as `llm_id`.\n\n## Tenant Models (v0.27.2)\n\nThese methods use the `/api/v1/models` routes and authenticate with `RAGFLOW_API_KEY`.\n\n```javascript\n// List the tenant's added models, optionally filtered by type\nconst added = await client.listAddedModels({ type: \"chat\" });\n// GET /api/v1/models?type=chat -> [{ name, model_type, provider_name, ... }]\n\n// List the tenant's default models\nconst defaults = await client.listDefaultModels();\n// GET /api/v1/models/default -> { default_models: [...] }\n\n// Set (or clear) the default model for a type\nawait client.setDefaultModel({\n  model_type: \"chat\",          // required: chat | embedding | rerank | asr | vision | tts | ocr\n  model_provider: \"OpenAI\",    // omit provider/instance/name to clear the default\n  model_instance: \"default\",\n  model_name: \"gpt-4o\",\n});\n// PATCH /api/v1/models/default\n```\n\n## Model Providers (v0.27.2)\n\nRAGFlow v0.27.2 provides provider/instance/model management under `/api/v1/providers`. All methods authenticate\nwith `RAGFLOW_API_KEY`. Path segments are URL-encoded, so model identifiers containing `@` or `/` are handled\nautomatically.\n\nIn v0.27.2, each provider instance supports `PUT` and `GET` on `/instances/{instance_id_or_name}` for updating a\nsingle instance's credentials; the CLI uses `GET /instances` to list and `POST /instances` to create.\n\n```javascript\n// List configured providers, or system-available providers with { available: true }\nawait client.listProviders({ available: true });        // GET /api/v1/providers?available=true\nawait client.getProvider(\"OpenAI\");                      // GET /api/v1/providers/OpenAI\nawait client.addProvider(\"OpenAI\");                      // PUT /api/v1/providers { provider_name }\nawait destructiveClient.deleteProvider(\"OpenAI\");                   // DELETE /api/v1/providers/OpenAI\n\n// Discover a provider's models (some providers fetch a live list from the remote API)\nawait client.listProviderModels(\"OpenAI\", { api_key: \"sk-...\", base_url: \"\" });\n\n// Instances hold a set of credentials (multiple API keys per provider are supported)\nawait client.listProviderInstances(\"OpenAI\");\nawait client.getProviderInstance(\"OpenAI\", \"default\");\nawait client.createProviderInstance(\"OpenAI\", {\n  instance_name: \"default\",    // required\n  api_key: \"sk-...\",           // required\n  base_url: \"\",\n  region: \"\",\n  model_info: [],\n});                                                       // POST /api/v1/providers/OpenAI/instances\nawait destructiveClient.deleteProviderInstances(\"OpenAI\", [\"default\"]);\n\n// Test a provider connection / API key without persisting an instance\nawait client.verifyProvider(\"OpenAI\", { api_key: \"sk-...\", base_url: \"\", region: \"default\" });\n\n// Manage the models on an instance\nawait client.listInstanceModels(\"OpenAI\", \"default\", { supported: true });\nawait client.addInstanceModel(\"OpenAI\", \"default\", {\n  model_name: \"gpt-4o\",        // required\n  model_type: \"chat\",          // required\n  max_tokens: 8192,\n  extra: {},\n});\nawait client.setInstanceModelStatus(\"OpenAI\", \"default\", \"gpt-4o\", \"enable\"); // PATCH .../models/<name>\n```\n\nTreat `api_key` values as sensitive: pass them in, but do not echo them back to the user.\n\n## System\n\n```javascript\n// Get the server version\nconst version = await client.getSystemVersion();\n\n// Check service health\nconst health = await client.getSystemHealth();\n\n// Inspect and update log levels\nconst levels = await client.getLogLevels();\nawait client.setLogLevel(\"ragflow\", \"DEBUG\");\n```\n\n`getSystemHealth()` handles RAGFlow's raw health JSON rather than the usual `{ code, data }` envelope. The health route checks reachability and server dependencies; use `validateConnection()` or an authenticated resource command to verify the API key.\n\n## Utility\n\n```javascript\n// Validate connection to RAGFlow server\nconst ok = await client.validateConnection();\n// Returns: true | false\n```\n\n## Configuration\n\nSet the following environment variables to configure the API client:\n```bash\nexport RAGFLOW_URL=https://your-ragflow-instance.com\nexport RAGFLOW_API_KEY=ragflow-xxxxx\n```\n\n`RAGFLOW_URL` should be the server root, for example `http://127.0.0.1:9380`. Bare hosts such as `localhost:9380` are normalized to `http://localhost:9380`. The client adds `/api/v1` for REST endpoints, including model discovery.\n\n### Security Best Practices\n\n- **Production: Use HTTPS.** Set `RAGFLOW_URL=https://...` for production deployments to protect the API key in transit.\n- **Dedicated keys.** Use a dedicated, rotatable automation key; RAGFlow API keys are tenant-scoped rather than permission-scoped.\n- **Protect secrets.** Never commit `RAGFLOW_API_KEY` to version control. Use environment variables or a `.env` file that is excluded from git.\n\nFile v3.0.0:references/COMMANDS.md\n\n# Command Reference\n\nDeletion commands, metadata removal or unscoped metadata updates, and ingestion with `--delete` require `--confirm-destructive` after the target operation is authorized. Missing or false confirmation fails before the destructive HTTP request. Ordinary reads and stopping parsing do not require it.\n\nPractical CLI reference for `scripts/ragflow.js`, organized around common RAGFlow workflows. It intentionally prioritizes daily operations over exhaustive REST API coverage.\n\nUse `--json` on any command to suppress status text and print only machine-readable JSON.\nJSON-valued options such as `--parser-config`, `--prompt-config`, and `--dsl` accept either inline JSON or `@path/to/file.json`.\n\nOn command failure with `--json`, the CLI exits non-zero and prints a structured error envelope:\n\n```json\n{\n  \"error\": {\n    \"message\": \"API Error: Unauthorized\",\n    \"raw_message\": \"Unauthorized\",\n    \"code\": 401,\n    \"status\": 401,\n    \"command\": \"list-models\"\n  }\n}\n```\n\n## Table of Contents\n\n- [Scenario Map](#scenario-map)\n- [Knowledge Base Setup](#knowledge-base-setup)\n- [Document Ingestion](#document-ingestion)\n- [Parsing and Chunking](#parsing-and-chunking)\n- [Information Retrieval](#information-retrieval)\n- [RAG Assistant Operation](#rag-assistant-operation)\n- [Agent Operation](#agent-operation)\n- [Embedded Website Access](#embedded-website-access)\n- [Discovery and Configuration](#discovery-and-configuration)\n- [System Operations](#system-operations)\n\n## Scenario Map\n\n| Scenario | Use it for |\n|---|---|\n| [Knowledge Base Setup](#knowledge-base-setup) | Create and maintain datasets before ingesting files |\n| [Document Ingestion](#document-ingestion) | Upload, inspect, update, and remove source documents |\n| [Parsing and Chunking](#parsing-and-chunking) | Turn documents into searchable chunks and manage chunk content |\n| [Information Retrieval](#information-retrieval) | Query datasets directly without creating a chat assistant |\n| [RAG Assistant Operation](#rag-assistant-operation) | Create chat assistants, manage sessions, and run Q&A |\n| [Agent Operation](#agent-operation) | Create tool-capable agents, manage sessions, and run agent chat |\n| [Embedded Website Access](#embedded-website-access) | Generate iframe/widget code and call shared chatbots/agentbots |\n| [Discovery and Configuration](#discovery-and-configuration) | Inspect available LLM models, and manage model providers/instances (v0.27.2) |\n| [System Operations](#system-operations) | Check health/version and inspect log-level settings |\n\n## Knowledge Base Setup\n\nUse this section when the user is creating or maintaining the dataset container that everything else depends on.\n\n```bash\nnode {baseDir}/scripts/ragflow.js create-dataset --name \"Tech Docs\" --chunk-method naive\nnode {baseDir}/scripts/ragflow.js create-dataset --name \"Tech Docs\" --embedding-model \"text-embedding-v4@Tongyi-Qianwen\"\nnode {baseDir}/scripts/ragflow.js list-datasets\nnode {baseDir}/scripts/ragflow.js get-dataset --id <id>\nnode {baseDir}/scripts/ragflow.js update-dataset --id <id> --name \"New Name\"\nnode {baseDir}/scripts/ragflow.js delete-datasets --ids <id1> <id2> --confirm-destructive\n```\n\nWhen you provide `--embedding-model` to a real v0.27.2 server, use the tenant model identifier format `<model_name>@<provider>`, for example `text-embedding-v4@Tongyi-Qianwen`. Use `list-models` to discover available model/provider pairs.\n\nTypical flow:\n\n1. `create-dataset`\n2. `list-datasets` or `get-dataset`\n3. `update-dataset` if metadata or chunk method needs adjustment\n4. `delete-datasets` only after explicit confirmation\n\n### `list-connectors`\n\nList connectors (tenant scope; no dataset required).\n\n**Options**: `--page`, `--page-size`, `--json`\n\n### `create-connector`\n\nCreate a connector (tenant scope; no dataset required).\n\n**Options**: `--config` (JSON file), `--json`\n\n**Example**: `node ragflow.js create-connector --config @connector.json --json`\n\nThe `--config` file is the complete request body, passed through verbatim. Use `name`, `source`, and nested `config` (not `type`). For example, v0.27.2's Sitemap connector:\n\n```json\n{\n  \"name\": \"Documentation sitemap\",\n  \"source\": \"sitemap\",\n  \"config\": {\n    \"sitemap_url\": \"https://example.com/sitemap.xml\",\n    \"follow_pdf_links\": false,\n    \"restrict_pdf_to_domain\": true\n  }\n}\n```\n\nOptional Sitemap settings include `url_filter` (regex), `batch_size`, and `user_agent`. For WebDAV, `config.ca_cert_path` points to a custom CA bundle **inside the RAGFlow container**, not on the CLI machine. Creating a connector does not attach it to a dataset or start ingestion; configure the dataset connection separately in RAGFlow.\n\n### `get-connector`, `update-connector`, `delete-connector`\n\nStandard CRUD operations.\n\n**Options**: `--id`, `--config` (for update), `--json`\n## Document Ingestion\n\nUse this section when the user needs to get files into a dataset or inspect document-level metadata.\n\n```bash\nnode {baseDir}/scripts/ragflow.js upload-documents --dataset <id> --files ./doc1.pdf ./doc2.txt\nnode {baseDir}/scripts/ragflow.js upload-documents --dataset <id> --files report.pdf=./tmp/task-output\nnode {baseDir}/scripts/ragflow.js ingest-documents --doc-ids <doc_id1> <doc_id2> --run 1\nnode {baseDir}/scripts/ragflow.js ingest-documents --doc-ids <doc_id1> --run 2\nnode {baseDir}/scripts/ragflow.js list-documents --dataset <id> --metadata-condition @metadata_condition.json\nnode {baseDir}/scripts/ragflow.js get-document --dataset <id> --id <doc_id>\nnode {baseDir}/scripts/ragflow.js update-document --dataset <id> --id <doc_id> --name \"New Name\"\nnode {baseDir}/scripts/ragflow.js update-document --dataset <id> --id <doc_id> --parser-config @parser_config.json --meta-fields @meta_fields.json\nnode {baseDir}/scripts/ragflow.js metadata-summary --dataset <id> --doc-ids <doc_id1> <doc_id2>\nnode {baseDir}/scripts/ragflow.js update-metadata --dataset <id> --config @metadata_update.json\nnode {baseDir}/scripts/ragflow.js delete-documents --dataset <id> --ids <doc_id1> --confirm-destructive\nnode {baseDir}/scripts/ragflow.js download-document --dataset <id> --id <doc_id> --output ./document.pdf\nnode {baseDir}/scripts/ragflow.js preview-document --id <doc_id> --output ./preview.pdf\n```\n\n`update-document` follows the current v0.27.2 RAGFlow route and sends `PATCH /api/v1/datasets/{dataset_id}/documents/{document_id}`. It accepts `name`, `parser_config`, `chunk_method`, `enabled`, and `meta_fields`.\n\n`ingest-documents` wraps `POST /api/v1/documents/ingest` for datasets configured with an ingestion pipeline. Use `--run 1` to start/rerun ingestion, `--run 2` to cancel ingestion, and `--delete` when rerunning should delete existing tasks and chunks first. Built-in chunking datasets should keep using `start-parsing` and `stop-parsing`.\n\n`list-documents` supports `metadata`, `metadata_condition`, `return_empty_metadata`, `orderby`, `desc`, `suffix`, `types`, and `run`.\n\nWhen the physical file path is a temporary or task-generated path, use `--files <original-name>=<path>` so RAGFlow stores the user-facing filename.\n\nUse this when you need to:\n\n- upload raw source files\n- inspect a document before parsing\n- rename or adjust a document record\n- delete a document by explicit ID\n\n## Parsing and Chunking\n\nUse this section after document upload, or when the user wants to control chunk generation directly.\n\nDownloads and previews return file bytes. With `--output <path>`, the CLI writes the bytes to a new file and returns metadata/path; existing files are never overwritten. Without `--output`, JSON contains `{ content, encoding: \"base64\", name, content_type, size }`. Choose a filename appropriate to the returned MIME type; previews can differ from the original file.\n\n### Parsing workflow\n\n```bash\nnode {baseDir}/scripts/ragflow.js start-parsing --dataset <id> --doc-ids <doc_id1>\nnode {baseDir}/scripts/ragflow.js stop-parsing --dataset <id> --doc-ids <doc_id1>\nnode {baseDir}/scripts/ragflow.js wait-parsing --dataset <id> --doc-ids <doc_id1> --timeout 120\n```\n\nParsing status is observable through `list-documents` by inspecting the `run` field: `UNSTART`, `RUNNING`, `CANCEL`, `DONE`, `FAIL`.\nThe `run` filter accepts either numeric values (`0`-`4`) or these text labels.\n\n### Chunk operations\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-chunks --dataset <id> --document <doc_id>\nnode {baseDir}/scripts/ragflow.js list-chunks --dataset <id> --document <doc_id> --id <chunk_id>\nnode {baseDir}/scripts/ragflow.js get-chunk --dataset <id> --document <doc_id> --chunk <chunk_id>\nnode {baseDir}/scripts/ragflow.js add-chunk --dataset <id> --document <doc_id> --content \"chunk content\"\nnode {baseDir}/scripts/ragflow.js update-chunk --dataset <id> --document <doc_id> --chunk <chunk_id> --content \"updated content\"\nnode {baseDir}/scripts/ragflow.js delete-chunks --dataset <id> --document <doc_id> --chunk-ids <id1> --confirm-destructive\nnode {baseDir}/scripts/ragflow.js get-document-graph --dataset <id> --document <doc_id>\nnode {baseDir}/scripts/ragflow.js delete-document-graph --dataset <id> --document <doc_id> --confirm-destructive\nnode {baseDir}/scripts/repro-delete-chunks.js --confirm-destructive\n```\n\n`update-chunk` uses the current `PATCH /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks/{chunk_id}` route. `get-document-graph` and `delete-document-graph` wrap the document structure graph routes under `/structure/graph`.\n\n`add-chunk` writes directly to the document store and returns the generated chunk ID immediately. On Elasticsearch/OpenSearch-style stores, exact `GET` by ID can see a new chunk before search/delete-by-query can see it because insert uses the store refresh cycle. `delete-chunks` handles this by retrying the transient response `rm_chunk deleted chunks 0, expect N` only after an exact ID lookup confirms the target chunk still exists. Tune this with `RAGFLOW_DELETE_CHUNK_RETRIES` and `RAGFLOW_DELETE_CHUNK_RETRY_DELAY_MS`.\n\nWith `--json`, `delete-chunks` returns a structured envelope instead of the bare server result:\n\n```json\n{\n  \"result\": {},\n  \"requested_chunk_ids\": [\"<chunk_id1>\"],\n  \"existing_chunk_ids\": [\"<chunk_id1>\"],\n  \"missing_chunk_ids\": [],\n  \"visibility_checked\": true,\n  \"retry_count\": 1,\n  \"retries\": [\n    {\n      \"attempt\": 0,\n      \"next_attempt\": 2,\n      \"max_retries\": 3,\n      \"existing_chunk_ids\": [\"<chunk_id1>\"],\n      \"missing_chunk_ids\": []\n    }\n  ]\n}\n```\n\nIf exact-ID checks prove that a target chunk is missing, the command exits non-zero and emits JSON containing `error`, `requested_chunk_ids`, `existing_chunk_ids`, `missing_chunk_ids`, `retry_count`, `retries`, and `delete_chunk_diagnostics`.\n\nIf a real server still returns `rm_chunk deleted chunks 0, expect 1` after retries, run `scripts/repro-delete-chunks.js --confirm-destructive`. The repro creates temporary resources, tries immediate deletion and retry/backoff without the client-side retry wrapper, prints a JSON diagnosis, and removes its dataset.\n\n### Chunk methods\n\n| Method | Use Case |\n|--------|----------|\n| `naive` | General chunking (default) |\n| `manual` | Manual documents |\n| `qna` | Q&A pairs |\n| `table` | Table data |\n| `paper` | Academic papers |\n| `book` | Books |\n| `laws` | Legal documents |\n| `presentation` | Presentations |\n| `picture` | Image OCR |\n| `one` | Whole document as one chunk |\n\n### `run-raptor`\n\nStart RAPTOR processing for a dataset.\n\n**Options**: `--dataset`, `--json`\n\n### `trace-raptor`\n\nCheck RAPTOR processing status.\n\n**Options**: `--dataset`, `--json`\n\n### GraphRAG lifecycle\n\n```bash\nnode {baseDir}/scripts/ragflow.js run-graphrag --dataset <id>\nnode {baseDir}/scripts/ragflow.js trace-graphrag --dataset <id>\nnode {baseDir}/scripts/ragflow.js get-knowledge-graph --dataset <id>\nnode {baseDir}/scripts/ragflow.js delete-knowledge-graph --dataset <id> --confirm-destructive\n```\n\nUse `delete-knowledge-graph` only after confirming the target dataset.\n## Information Retrieval\n\nUse this section when the user wants retrieval results directly instead of creating a chat assistant or agent.\n\n```bash\n# Basic retrieval\nnode {baseDir}/scripts/ragflow.js retrieve --question \"What is RAG?\" --datasets <id>\n\n# Advanced retrieval with keyword + knowledge graph\nnode {baseDir}/scripts/ragflow.js retrieve \\\n  --question \"machine learning algorithms\" \\\n  --datasets <id1> <id2> \\\n  --similarity 0.3 \\\n  --top-n 10 \\\n  --rerank <rerank_model_id> \\\n  --keyword \\\n  --kg\n```\n\n### Retrieval parameters\n\n| Parameter | Short | Default | Description |\n|-----------|-------|---------|-------------|\n| `--question` | `-q` | - | Search question (required) |\n| `--datasets` | `-d` | - | Dataset IDs |\n| `--similarity` | `-s` | 0.2 | Similarity threshold (0-1) |\n| `--top-n` | `-n` | 30 | Number of retrieved chunks; sent as RAGFlow `page_size` |\n| `--knn-top-k` | | 1024 | Vector-neighbor count; preferred in v0.27.2 |\n| `--knn-num-candidates` | | max(2048, knn_top_k) | ANN candidate pool; must be at least knn_top_k |\n| `--rerank-candidates-count` | | 64 | Candidate count; must be at least page × page_size |\n| `--page` | | 1 | Result page (positive integer) |\n| `--doc-ids` | | - | Restrict to document IDs |\n| `--metadata-condition` | | - | JSON or @file metadata filter; intersects document IDs |\n| `--highlight` | | false | Include highlighted matches; accepts false |\n| `--include-knowledge-compilation` | | true | Include compiled chunks; pass false for raw document chunks |\n| `--vector-weight` | `-w` | 0.3 | Vector similarity weight (0-1) |\n| `--rerank` | `-r` | - | Rerank model ID |\n| `--keyword` | | false | Enable keyword search |\n| `--kg` | | false | Enable knowledge graph; sent as RAGFlow `use_kg` |\n| `--cross-langs` | | - | Cross-language targets |\n\nDefaults above are server defaults; omitted flags are not sent. For example, `--page 3 --top-n 30 --rerank-candidates-count 90` covers the requested page. The API still expects similarity and vector weights on a 0–1 scale even though the UI displays percentages. Results are an object with `chunks`, `total`, and `doc_aggs`.\n\n## RAG Assistant Operation\n\nUse this section when the user wants a dataset-backed chat assistant with reusable sessions.\n\n### Assistant lifecycle\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-chats\nnode {baseDir}/scripts/ragflow.js create-chat --name \"Tech Q&A\" --datasets <id1> <id2> --llm-id qwen-turbo@Tongyi-Qianwen\nnode {baseDir}/scripts/ragflow.js get-chat --id <chat_id>\nnode {baseDir}/scripts/ragflow.js update-chat --id <chat_id> --name \"New Name\"\nnode {baseDir}/scripts/ragflow.js update-chat --id <chat_id> --prompt-config @prompt_config.json\nnode {baseDir}/scripts/ragflow.js patch-chat --id <chat_id> --prompt \"Use the dataset\"\nnode {baseDir}/scripts/ragflow.js delete-chats --ids <id1> <id2> --confirm-destructive\n```\n\nUse the tenant model identifier format `<model_name>@<provider>` for `--llm-id`. The current model catalog can return numeric model row IDs; do not pass those numeric IDs to `create-chat`.\n\n### Session management\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-sessions --chat <chat_id>\nnode {baseDir}/scripts/ragflow.js create-session --chat <chat_id> --name \"New Session\"\nnode {baseDir}/scripts/ragflow.js get-session --chat <chat_id> --session <session_id>\nnode {baseDir}/scripts/ragflow.js update-session --chat <chat_id> --session <session_id> --name \"Reviewed Session\"\nnode {baseDir}/scripts/ragflow.js delete-sessions --chat <chat_id> --ids <session_id1> --confirm-destructive\n```\n\n### Ask the assistant\n\n```bash\nnode {baseDir}/scripts/ragflow.js chat --chat <chat_id> --session <session_id> --question \"Hello\"\nnode {baseDir}/scripts/ragflow.js chat-session --chat <chat_id> --session <session_id> --messages @session_messages.json\nnode {baseDir}/scripts/ragflow.js chat-session --chat <chat_id> --session <session_id> --question \"Hello\"\n```\n\n`chat-session` uses `POST /api/v1/chat/completions` with `chat_id` and `session_id` in the body. When `--messages` is provided, the CLI extracts the last `role: \"user\"` message as `question`; use `--question` when you already have a single user prompt.\n\n`--pass-all-history` sets `pass_all_history_messages: true`, which replaces the entire stored history with the submitted messages array instead of appending only the latest message (the default behavior in v0.27.2).\n\n\nUse this path when the user wants multi-turn Q&A over documents without building a full agent workflow.\n\n## Agent Operation\n\nUse this section when the user wants a more autonomous workflow built around an agent DSL and agent sessions.\n\nFor a practical guide to the current canvas schema, variable rules, webhook mode, and minimal working DSL files, read [AGENT_GUIDE.md](AGENT_GUIDE.md).\n\n### Agent lifecycle\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-agents\nnode {baseDir}/scripts/ragflow.js create-agent --title \"Assistant\" --dsl '<dsl_json>'\nnode {baseDir}/scripts/ragflow.js create-agent --title \"Assistant\" --dsl @agent_dsl.json\nnode {baseDir}/scripts/ragflow.js create-agent --title \"Assistant\" --dsl @agent_dsl.json --canvas-type \"\"\nnode {baseDir}/scripts/ragflow.js get-agent --id <agent_id>\nnode {baseDir}/scripts/ragflow.js update-agent --id <agent_id> --title \"New Name\"\nnode {baseDir}/scripts/ragflow.js update-agent --id <agent_id> --canvas-type \"flow\"\nnode {baseDir}/scripts/ragflow.js delete-agents --ids <id1> <id2> --confirm-destructive\n```\n\n**Options for `list-agents`**:\n\n| Option | Description |\n|---|---|\n| `--tags` | Filter agents by tags (comma-separated) |\n`agent-chat` uses `POST /api/v1/agents/chat/completions` with `agent_id` in the JSON body.\n\nAgents require a DSL workflow definition. A minimal current-schema DSL:\n\n```json\n{\n  \"components\": {\n    \"begin\": {\n      \"obj\": {\n        \"component_name\": \"Begin\",\n        \"params\": {\n          \"mode\": \"conversational\",\n          \"prologue\": \"Hello\"\n        }\n      },\n      \"downstream\": [\"message:0\"],\n      \"upstream\": []\n    },\n    \"message:0\": {\n      \"obj\": {\n        \"component_name\": \"Message\",\n        \"params\": {\n          \"content\": [\"Hello from RAGFlow\"]\n        }\n      },\n      \"downstream\": [],\n      \"upstream\": [\"begin\"]\n    }\n  },\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"edges\": [],\n    \"nodes\": [\n      {\n        \"id\": \"begin\",\n        \"type\": \"beginNode\",\n        \"position\": { \"x\": 50, \"y\": 200 },\n        \"data\": {\n          \"label\": \"Begin\",\n          \"name\": \"begin\",\n          \"form\": {\n            \"mode\": \"conversational\",\n            \"prologue\": \"Hello\"\n          }\n        }\n      },\n      {\n        \"id\": \"message:0\",\n        \"type\": \"messageNode\",\n        \"position\": { \"x\": 320, \"y\": 200 },\n        \"data\": {\n          \"label\": \"Message\",\n          \"name\": \"message_0\",\n          \"form\": {\n            \"content\": [\"Hello from RAGFlow\"]\n          }\n        }\n      }\n    ]\n  }\n}\n```\n\nThe full practical guide and additional minimal examples live in:\n\n- `references/AGENT_GUIDE.md`\n- `references/examples/agents/01-conversational-message.json`\n- `references/examples/agents/02-retrieval-message.json`\n- `references/examples/agents/03-tool-agent.json`\n- `references/examples/agents/04-iteration-agent.json`\n- `references/examples/agents/05-webhook-message.json`\n\nFor iteration flows, prefer the `04-iteration-agent.json` pattern where an upstream `Agent` emits an object with an `items` array and `Iteration.params.items_ref` points to `agent:0@structured.items`.\n\n### `list-agent-tags`\n\nList all agent tags with usage counts.\n\n**Options**: `--json`\n\n**Example**: `node ragflow.js list-agent-tags --json`\n\n### `update-agent-tags`\n\nUpdate tags for an agent.\n\n**Options**: `--id`, `--tags` (comma-separated), `--json`\n\n**Example**: `node ragflow.js update-agent-tags --id <agent_id> --tags ml,rag --json`\n### Agent session management\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-agent-sessions --agent <agent_id>\nnode {baseDir}/scripts/ragflow.js create-agent-session --agent <agent_id>\nnode {baseDir}/scripts/ragflow.js delete-agent-sessions --agent <agent_id> --ids <session_id1> --confirm-destructive\n```\n\n### Ask the agent\n\n```bash\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\"\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\" --stream false\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\" --chat-template-kwargs '{\"temperature\": 0.5}'\n```\n\n`--stream false` requests the final JSON result directly. The bundled client normalizes current `workflow_finished` envelopes into `{ answer, reference, session_id, id }`.\n\nUse this path when the user explicitly wants an agent workflow instead of a simple retrieval assistant.\n\n## Embedded Website Access\n\nUse this section when the user wants the same website embed behavior as RAGFlow's \"Embed into site\" UI. These commands use `/api/v1/system/tokens` to obtain a token with `beta`, then call the shared `/api/v1/chatbots/*` or `/api/v1/agentbots/*` routes with `Authorization: Bearer <beta>`.\n\n### Token management\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-system-tokens\nnode {baseDir}/scripts/ragflow.js create-system-token\nnode {baseDir}/scripts/ragflow.js delete-system-token --token-file token.txt --confirm-destructive\ncat token.txt | node {baseDir}/scripts/ragflow.js delete-system-token --token-stdin --confirm-destructive\n```\n\n`delete-system-token` reads the token from stdin or a file so the secret never needs to appear in argv. Prefer `--token-stdin` for ad hoc use and `--token-file` when you already store the token in a local file.\n\n`embed-*` commands accept `--beta <token>` when you already have the embedded auth token. Without `--beta`, the CLI reuses the first system token with `beta`; if none exists, it creates one. Treat both the normal system token and the `beta` value as sensitive.\n\n`RAGFLOW_URL` may be a full origin such as `http://localhost:9380` or a bare host such as `localhost:9380`; the CLI normalizes bare hosts to `http://...` when generating iframe URLs.\n\nFor `embed-code`, `--origin` is the public web origin that serves the shared chat or agent page. If `--origin` is omitted, the CLI falls back to `RAGFLOW_URL`. On split deployments where the API base URL and browser-facing web origin differ, pass `--origin` explicitly.\n\n### Generate embed code\n\n```bash\nnode {baseDir}/scripts/ragflow.js embed-code --chat <chat_id> --type fullscreen\nnode {baseDir}/scripts/ragflow.js embed-code --agent <agent_id> --type widget --published --streaming --user-id <user_id>\n```\n\nCommon options:\n\n| Option | Description |\n|--------|-------------|\n| `--chat` / `--agent` | Target chat assistant or agent. Provide exactly one. |\n| `--type` | `fullscreen` or `widget`; defaults to `fullscreen`. |\n| `--origin` | Public RAGFlow origin for iframe URLs; defaults to `RAGFLOW_URL`. |\n| `--theme` | `light` or `dark` for fullscreen embeds. |\n| `--locale` | Locale query parameter. |\n| `--hide-avatar` | Adds RAGFlow's `visible_avatar=1` shared-page flag. |\n| `--published` | Uses the published agent release when embedding agents. |\n| `--streaming` | Enables streaming for widget embeds. |\n| `--data` | JSON object appended as `data_<key>=<value>` query parameters. |\n\nWhen presenting results to the user, do not paste raw `token`, `beta`, `src`, or iframe HTML with `auth=` unless the user explicitly asks for the secret material. Use the raw CLI output for execution, but summarize it for the user.\n\n### Inspect and call embedded bots\n\n```bash\nnode {baseDir}/scripts/ragflow.js embed-info --chat <chat_id>\nnode {baseDir}/scripts/ragflow.js embed-info --agent <agent_id>\nnode {baseDir}/scripts/ragflow.js embed-chat --chat <chat_id> --question \"Hello\"\nnode {baseDir}/scripts/ragflow.js embed-chat --chat <chat_id> --question \"Hello\" --stream false\nnode {baseDir}/scripts/ragflow.js embed-agent-chat --agent <agent_id> --question \"Hello\" --inputs @begin_inputs.json\n```\n\n`embed-chat` accepts `--session`, `--conversation-id`, `--quote`, `--reasoning`, `--internet`, and `--stream false`. `embed-agent-chat` accepts `--session`, `--inputs`, `--user-id`, `--published`, and `--stream false`.\n\nWhen `--session` is omitted, `embed-chat` first calls the embedded chatbot route with an empty question to create the embedded session, captures `session_id`, and then sends the real question. This mirrors RAGFlow's shared-site iframe behavior. The first no-session response is only the prologue; call the route with `session_id` when implementing your own client.\n\n`embed-info`, `embed-chat`, and `embed-agent-chat` may internally reuse or create embed auth material when `--beta` is omitted. This is expected CLI behavior for automated workflows; summarize the outcome for the user without echoing the secret values by default.\n\n## Discovery and Configuration\n\nUse this section when the user needs to inspect available models before creating datasets, assistants, or agents.\n\n```bash\nnode {baseDir}/scripts/ragflow.js list-models\nnode {baseDir}/scripts/ragflow.js list-models --include-details\nnode {baseDir}/scripts/ragflow.js list-models --group-by factory\nnode {baseDir}/scripts/ragflow.js list-models --type embedding\n```\n\n`list-models` lists configured models, grouped by type or factory. Use its `identifier` (`<model>@<instance>@<provider>`) directly in create operations; the two-part `<model>@<provider>` form selects the default instance. Distinct instances remain separate even when model names match. `--include-details` adds returned tenant/provider/instance IDs and rank locally; it does not send an unsupported `include_details` query. `--all` retains rows explicitly marked unavailable, but the catalog may omit availability state: `configured` is not a successful connection test. Use `verify-provider` for a connection check.\n\nRAGFlow v0.27.2 exposes model discovery at `/api/v1/models` (the legacy `/v1/llm/my_llms` route was removed in v0.27.0; the CLI no longer calls it). Authentication uses `RAGFLOW_API_KEY`.\n\nFor create operations, use model names plus provider suffixes such as `qwen-turbo@Tongyi-Qianwen` or `text-embedding-v4@Tongyi-Qianwen`. If `list-models` shows numeric `model_id` fields, treat them as server row IDs, not values for `--llm-id` or `--embedding-model`.\n\n### Tenant models (v0.27.2)\n\nThese commands use the `/api/v1/models` routes (the same routes `list-models` uses).\n\n| Command | Purpose | Options |\n|---------|---------|---------|\n| `list-added-models` | List the tenant's added models | `--type` (filter), `--json` |\n| `list-default-models` | List the tenant's default models | `--json` |\n| `set-default-model` | Set or clear the default model for a type | `--model-type` (required), `--model-provider`, `--model-instance`, `--model-name`, `--json` |\n\n`set-default-model` requires `--model-type` (one of `chat`, `embedding`, `rerank`, `asr`, `vision`, `tts`, `ocr`). Provide `--model-provider`, `--model-instance`, and `--model-name` to set a default; omit them to clear it.\n\n### Model providers (v0.27.2)\n\nv0.27.2 provides provider/instance/model management under `/api/v1/providers`. An \"instance\" holds one set of credentials, and a provider can have multiple instances (multiple API keys). Instances are now individually addressable as `/instances/<id_or_name>` with `GET`/`PUT` support.\n\n| Command | Purpose | Options |\n|---------|---------|---------|\n| `list-providers` | List configured providers, or `--available` system providers | `--available`, `--json` |\n| `get-provider` | Get provider details | `--name` (required), `--json` |\n| `add-provider` | Add a provider for the tenant | `--name` (required), `--json` |\n| `delete-provider` | Remove a provider | `--name` (required), `--json` |\n| `list-provider-models` | List a provider's available models | `--name` (required), `--api-key-file`, `--base-url`, `--json` |\n| `list-provider-instances` | List a provider's instances | `--name` (required), `--json` |\n| `get-provider-instance` | Get one instance | `--name`, `--instance` (both required), `--json` |\n| `create-provider-instance` | Create an instance with credentials | `--name`, `--instance`, provider key via env/file, `--base-url`, `--region`, `--model-info` (JSON), `--json` |\n| `delete-provider-instances` | Remove instances | `--name` (required), `--instances` (multiple, required), `--json` |\n| `verify-provider` | Test a connection / API key without persisting | `--name`, provider key via env/file, `--base-url`, `--region`, `--json` |\n| `list-instance-models` | List models on an instance | `--name`, `--instance` (required), `--supported`, `--json` |\n| `add-instance-model` | Add a model to an instance | `--name`, `--instance`, `--model-name`, `--model-type` (required), `--max-tokens`, `--extra` (JSON), `--json` |\n| `set-model-status` | Enable or disable an instance model | `--name`, `--instance`, `--model-name`, `--status` (required), `--json` |\n\n**Example**: `node ragflow.js create-provider-instance --name OpenAI --instance default --api-key-file provider-key.txt --json`\n\nPrefer `RAGFLOW_PROVIDER_API_KEY` or `--api-key-file`; both keep provider credentials out of the process command line. The command-line `--api-key` parameter is not supported. The skill does not wrap the provider \"chat to model\" test endpoint (`POST /providers/<name>/instances/<instance>/models/<model_name>`); use `chat-session` or `agent-chat` to exercise a configured model instead.\n\n## System Operations\n\nUse this section when the user needs a quick connectivity check, version information, or log-level configuration.\n\n```bash\nnode {baseDir}/scripts/ragflow.js system-health --json\nnode {baseDir}/scripts/ragflow.js system-version\nnode {baseDir}/scripts/ragflow.js get-log-levels\nnode {baseDir}/scripts/ragflow.js set-log-level --pkg-name ragflow --level INFO\n```\n\nFile v3.0.0:references/examples/agents/01-conversational-message.json\n\n{\n  \"components\": {\n    \"begin\": {\n      \"obj\": {\n        \"component_name\": \"Begin\",\n        \"params\": {\n          \"mode\": \"conversational\",\n          \"prologue\": \"Hi! I'm your assistant.\"\n        }\n      },\n      \"downstream\": [\n        \"message:0\"\n      ],\n      \"upstream\": []\n    },\n    \"message:0\": {\n      \"obj\": {\n        \"component_name\": \"Message\",\n        \"params\": {\n          \"content\": [\n            \"你好，我是一个最小可用的 RAGFlow 智能体示例。\"\n          ]\n        }\n      },\n      \"downstream\": [],\n      \"upstream\": [\n        \"begin\"\n      ]\n    }\n  },\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [\n      {\n        \"id\": \"begin\",\n        \"type\": \"beginNode\",\n        \"position\": {\n          \"x\": 50,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Begin\",\n          \"name\": \"begin\",\n          \"form\": {\n            \"mode\": \"conversational\",\n            \"prologue\": \"Hi! I'm your assistant.\"\n          }\n        }\n      },\n      {\n        \"id\": \"message:0\",\n        \"type\": \"messageNode\",\n        \"position\": {\n          \"x\": 320,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Message\",\n          \"name\": \"message_0\",\n          \"form\": {\n            \"content\": [\n              \"你好，我是一个最小可用的 RAGFlow 智能体示例。\"\n            ]\n          }\n        }\n      }\n    ],\n    \"edges\": [\n      {\n        \"id\": \"begin-message:0\",\n        \"source\": \"begin\",\n        \"target\": \"message:0\"\n      }\n    ]\n  }\n}\n\nFile v3.0.0:references/examples/agents/02-retrieval-message.json\n\n{\n  \"components\": {\n    \"begin\": {\n      \"obj\": {\n        \"component_name\": \"Begin\",\n        \"params\": {\n          \"mode\": \"conversational\",\n          \"prologue\": \"Hi! Ask me about the dataset.\"\n        }\n      },\n      \"downstream\": [\n        \"retrieval:0\"\n      ],\n      \"upstream\": []\n    },\n    \"retrieval:0\": {\n      \"obj\": {\n        \"component_name\": \"Retrieval\",\n        \"params\": {\n          \"query\": \"{sys.query}\",\n          \"similarity_threshold\": 0.2,\n          \"keywords_similarity_weight\": 0.3,\n          \"top_n\": 8,\n          \"top_k\": 1024,\n          \"kb_ids\": [\n            \"your-dataset-id\"\n          ],\n          \"rerank_id\": \"\",\n          \"empty_response\": \"No relevant chunks found.\",\n          \"use_kg\": false,\n          \"toc_enhance\": false,\n          \"cross_languages\": [],\n          \"retrieval_from\": \"dataset\"\n        }\n      },\n      \"downstream\": [\n        \"message:0\"\n      ],\n      \"upstream\": [\n        \"begin\"\n      ]\n    },\n    \"message:0\": {\n      \"obj\": {\n        \"component_name\": \"Message\",\n        \"params\": {\n          \"content\": [\n            \"{retrieval:0@formalized_content}\"\n          ]\n        }\n      },\n      \"downstream\": [],\n      \"upstream\": [\n        \"retrieval:0\"\n      ]\n    }\n  },\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [\n      {\n        \"id\": \"begin\",\n        \"type\": \"beginNode\",\n        \"position\": {\n          \"x\": 50,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Begin\",\n          \"name\": \"begin\",\n          \"form\": {\n            \"mode\": \"conversational\",\n            \"prologue\": \"Hi! Ask me about the dataset.\"\n          }\n        }\n      },\n      {\n        \"id\": \"retrieval:0\",\n        \"type\": \"retrievalNode\",\n        \"position\": {\n          \"x\": 320,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Retrieval\",\n          \"name\": \"retrieval_0\",\n          \"form\": {\n            \"query\": \"{sys.query}\",\n            \"similarity_threshold\": 0.2,\n            \"keywords_similarity_weight\": 0.3,\n            \"top_n\": 8,\n            \"top_k\": 1024,\n            \"kb_ids\": [\n              \"your-dataset-id\"\n            ],\n            \"rerank_id\": \"\",\n            \"empty_response\": \"No relevant chunks found.\",\n            \"use_kg\": false,\n            \"toc_enhance\": false,\n            \"cross_languages\": [],\n            \"retrieval_from\": \"dataset\"\n          }\n        }\n      },\n      {\n        \"id\": \"message:0\",\n        \"type\": \"messageNode\",\n        \"position\": {\n          \"x\": 610,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Message\",\n          \"name\": \"message_0\",\n          \"form\": {\n            \"content\": [\n              \"{retrieval:0@formalized_content}\"\n            ]\n          }\n        }\n      }\n    ],\n    \"edges\": [\n      {\n        \"id\": \"begin-retrieval:0\",\n        \"source\": \"begin\",\n        \"target\": \"retrieval:0\"\n      },\n      {\n        \"id\": \"retrieval:0-message:0\",\n        \"source\": \"retrieval:0\",\n        \"target\": \"message:0\"\n      }\n    ]\n  }\n}\n\nFile v3.0.0:references/examples/agents/03-tool-agent.json\n\n{\n  \"components\": {\n    \"begin\": {\n      \"obj\": {\n        \"component_name\": \"Begin\",\n        \"params\": {\n          \"mode\": \"conversational\",\n          \"prologue\": \"Hi! I can answer directly or call a tool.\"\n        }\n      },\n      \"downstream\": [\n        \"agent:0\"\n      ],\n      \"upstream\": []\n    },\n    \"agent:0\": {\n      \"obj\": {\n        \"component_name\": \"Agent\",\n        \"params\": {\n          \"llm_id\": \"your-chat-model@provider\",\n          \"sys_prompt\": \"You are a helpful assistant. Use the retrieval tool when the user asks about private knowledge.\",\n          \"prompts\": [\n            {\n              \"role\": \"user\",\n              \"content\": \"{sys.query}\"\n            }\n          ],\n          \"max_tokens\": 256,\n          \"temperature\": 0.1,\n          \"top_p\": 0.3,\n          \"presence_penalty\": 0,\n          \"frequency_penalty\": 0,\n          \"max_retries\": 3,\n          \"delay_after_error\": 1,\n          \"max_rounds\": 1,\n          \"description\": \"Minimal tool-enabled agent\",\n          \"user_prompt\": \"\",\n          \"visual_files_var\": \"\",\n          \"tools\": [\n            {\n              \"component_name\": \"Retrieval\",\n              \"id\": \"Retrieval:tool0\",\n              \"name\": \"Retrieval\",\n              \"params\": {\n                \"description\": \"\",\n                \"similarity_threshold\": 0.2,\n                \"keywords_similarity_weight\": 0.3,\n                \"top_n\": 8,\n                \"top_k\": 1024,\n                \"kb_ids\": [\n                  \"your-dataset-id\"\n                ],\n                \"rerank_id\": \"\",\n                \"empty_response\": \"No relevant chunks found.\",\n                \"use_kg\": false,\n                \"toc_enhance\": false,\n                \"cross_languages\": [],\n                \"retrieval_from\": \"dataset\"\n              }\n            }\n          ],\n          \"mcp\": [],\n          \"cite\": true\n        }\n      },\n      \"downstream\": [\n        \"message:0\"\n      ],\n      \"upstream\": [\n        \"begin\"\n      ]\n    },\n    \"message:0\": {\n      \"obj\": {\n        \"component_name\": \"Message\",\n        \"params\": {\n          \"content\": [\n            \"{agent:0@content}\"\n          ]\n        }\n      },\n      \"downstream\": [],\n      \"upstream\": [\n        \"agent:0\"\n      ]\n    }\n  },\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [\n      {\n        \"id\": \"begin\",\n        \"type\": \"beginNode\",\n        \"position\": {\n          \"x\": 50,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Begin\",\n          \"name\": \"begin\",\n          \"form\": {\n            \"mode\": \"conversational\",\n            \"prologue\": \"Hi! I can answer directly or call a tool.\"\n          }\n        }\n      },\n      {\n        \"id\": \"agent:0\",\n        \"type\": \"agentNode\",\n        \"position\": {\n          \"x\": 340,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Agent\",\n          \"name\": \"agent_0\",\n          \"form\": {\n            \"llm_id\": \"your-chat-model@provider\",\n            \"sys_prompt\": \"You are a helpful assistant. Use the retrieval tool when the user asks about private knowledge.\",\n            \"prompts\": [\n              {\n                \"role\": \"user\",\n                \"content\": \"{sys.query}\"\n              }\n            ],\n            \"max_tokens\": 256,\n            \"temperature\": 0.1,\n            \"top_p\": 0.3,\n            \"presence_penalty\": 0,\n            \"frequency_penalty\": 0,\n            \"max_retries\": 3,\n            \"delay_after_error\": 1,\n            \"max_rounds\": 1,\n            \"description\": \"Minimal tool-enabled agent\",\n            \"user_prompt\": \"\",\n            \"visual_files_var\": \"\",\n            \"tools\": [\n              {\n                \"component_name\": \"Retrieval\",\n                \"id\": \"Retrieval:tool0\",\n                \"name\": \"Retrieval\",\n                \"params\": {\n                  \"description\": \"\",\n                  \"similarity_threshold\": 0.2,\n                  \"keywords_similarity_weight\": 0.3,\n                  \"top_n\": 8,\n                  \"top_k\": 1024,\n                  \"kb_ids\": [\n                    \"your-dataset-id\"\n                  ],\n                  \"rerank_id\": \"\",\n                  \"empty_response\": \"No relevant chunks found.\",\n                  \"use_kg\": false,\n                  \"toc_enhance\": false,\n                  \"cross_languages\": [],\n                  \"retrieval_from\": \"dataset\"\n                }\n              }\n            ],\n            \"mcp\": [],\n            \"cite\": true\n          }\n        }\n      },\n      {\n        \"id\": \"message:0\",\n        \"type\": \"messageNode\",\n        \"position\": {\n          \"x\": 650,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Message\",\n          \"name\": \"message_0\",\n          \"form\": {\n            \"content\": [\n              \"{agent:0@content}\"\n            ]\n          }\n        }\n      }\n    ],\n    \"edges\": [\n      {\n        \"id\": \"begin-agent:0\",\n        \"source\": \"begin\",\n        \"target\": \"agent:0\"\n      },\n      {\n        \"id\": \"agent:0-message:0\",\n        \"source\": \"agent:0\",\n        \"target\": \"message:0\"\n      }\n    ]\n  }\n}\n\nFile v3.0.0:references/examples/agents/04-iteration-agent.json\n\n{\n  \"components\": {\n    \"begin\": {\n      \"obj\": {\n        \"component_name\": \"Begin\",\n        \"params\": {\n          \"mode\": \"conversational\",\n          \"prologue\": \"Hi! I can break the task into sub-topics.\"\n        }\n      },\n      \"downstream\": [\n        \"agent:0\"\n      ],\n      \"upstream\": []\n    },\n    \"agent:0\": {\n      \"obj\": {\n        \"component_name\": \"Agent\",\n        \"params\": {\n          \"llm_id\": \"your-chat-model@provider\",\n          \"sys_prompt\": \"Return only valid JSON in the form {\\\"items\\\":[\\\"topic1\\\",\\\"topic2\\\"]}. Extract 2-3 short sub-topics from the user query.\",\n          \"prompts\": [\n            {\n              \"role\": \"user\",\n              \"content\": \"{sys.query}\"\n            }\n          ],\n          \"max_tokens\": 256,\n          \"temperature\": 0.1,\n          \"top_p\": 0.3,\n          \"presence_penalty\": 0,\n          \"frequency_penalty\": 0,\n          \"max_retries\": 3,\n          \"delay_after_error\": 1,\n          \"max_rounds\": 1,\n          \"tools\": [],\n          \"mcp\": [],\n          \"cite\": false,\n          \"outputs\": {\n            \"structured\": {\n              \"type\": \"object\",\n              \"properties\": {\n                \"items\": {\n                  \"type\": \"array\",\n                  \"items\": {\n                    \"type\": \"string\"\n                  }\n                }\n              },\n              \"required\": [\n                \"items\"\n              ]\n            }\n          }\n        }\n      },\n      \"downstream\": [\n        \"iteration:0\"\n      ],\n      \"upstream\": [\n        \"begin\"\n      ]\n    },\n    \"iteration:0\": {\n      \"obj\": {\n        \"component_name\": \"Iteration\",\n        \"params\": {\n          \"items_ref\": \"agent:0@structured.items\",\n          \"outputs\": {\n            \"reports\": {\n              \"type\": \"Array<string>\",\n              \"ref\": \"agent:1@content\"\n            }\n          }\n        }\n      },\n      \"downstream\": [\n        \"message:0\"\n      ],\n      \"upstream\": [\n        \"agent:0\"\n      ]\n    },\n    \"iterationitem:0\": {\n      \"obj\": {\n        \"component_name\": \"IterationItem\",\n        \"params\": {\n          \"outputs\": {\n            \"index\": {\n              \"type\": \"integer\"\n            },\n            \"item\": {\n              \"type\": \"unknown\"\n            }\n          }\n        }\n      },\n      \"parent_id\": \"iteration:0\",\n      \"downstream\": [\n        \"agent:1\"\n      ],\n      \"upstream\": []\n    },\n    \"agent:1\": {\n      \"obj\": {\n        \"component_name\": \"Agent\",\n        \"params\": {\n          \"llm_id\": \"your-chat-model@provider\",\n          \"sys_prompt\": \"Write one short sentence about this sub-topic: {iterationitem:0@item}\",\n          \"prompts\": [\n            {\n              \"role\": \"user\",\n              \"content\": \"{iterationitem:0@item}\"\n            }\n          ],\n          \"max_tokens\": 128,\n          \"temperature\": 0.1,\n          \"top_p\": 0.3,\n          \"presence_penalty\": 0,\n          \"frequency_penalty\": 0,\n          \"max_retries\": 3,\n          \"delay_after_error\": 1,\n          \"max_rounds\": 1,\n          \"tools\": [],\n          \"mcp\": [],\n          \"cite\": false\n        }\n      },\n      \"parent_id\": \"iteration:0\",\n      \"downstream\": [\n        \"iterationitem:0\"\n      ],\n      \"upstream\": [\n        \"iterationitem:0\"\n      ]\n    },\n    \"message:0\": {\n      \"obj\": {\n        \"component_name\": \"Message\",\n        \"params\": {\n          \"content\": [\n            \"{iteration:0@reports}\"\n          ]\n        }\n      },\n      \"downstream\": [],\n      \"upstream\": [\n        \"iteration:0\"\n      ]\n    }\n  },\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [\n      {\n        \"id\": \"begin\",\n        \"type\": \"beginNode\",\n        \"position\": {\n          \"x\": 50,\n          \"y\": 220\n        },\n        \"data\": {\n          \"label\": \"Begin\",\n          \"name\": \"begin\",\n          \"form\": {\n            \"mode\": \"conversational\",\n            \"prologue\": \"Hi! I can break the task into sub-topics.\"\n          }\n        }\n      },\n      {\n        \"id\": \"agent:0\",\n        \"type\": \"agentNode\",\n        \"position\": {\n          \"x\": 320,\n          \"y\": 220\n        },\n        \"data\": {\n          \"label\": \"Agent\",\n          \"name\": \"agent_0\",\n          \"form\": {\n            \"llm_id\": \"your-chat-model@provider\",\n            \"sys_prompt\": \"Return only valid JSON in the form {\\\"items\\\":[\\\"topic1\\\",\\\"topic2\\\"]}. Extract 2-3 short sub-topics from the user query.\",\n            \"prompts\": [\n              {\n                \"role\": \"user\",\n                \"content\": \"{sys.query}\"\n              }\n            ],\n            \"max_tokens\": 256,\n            \"temperature\": 0.1,\n            \"top_p\": 0.3,\n            \"presence_penalty\": 0,\n            \"frequency_penalty\": 0,\n            \"max_retries\": 3,\n            \"delay_after_error\": 1,\n            \"max_rounds\": 1,\n            \"tools\": [],\n            \"mcp\": [],\n            \"cite\": false,\n            \"outputs\": {\n              \"structured\": {\n                \"type\": \"object\",\n                \"properties\": {\n                  \"items\": {\n                    \"type\": \"array\",\n                    \"items\": {\n                      \"type\": \"string\"\n                    }\n                  }\n                },\n                \"required\": [\n                  \"items\"\n                ]\n              }\n            }\n          }\n        }\n      },\n      {\n        \"id\": \"iteration:0\",\n        \"type\": \"group\",\n        \"position\": {\n          \"x\": 620,\n          \"y\": 120\n        },\n        \"data\": {\n          \"label\": \"Iteration\",\n          \"name\": \"iteration_0\",\n          \"form\": {\n            \"items_ref\": \"agent:0@structured.items\",\n            \"outputs\": {\n              \"reports\": {\n                \"type\": \"Array<string>\",\n                \"ref\": \"agent:1@content\"\n              }\n            }\n          }\n        }\n      },\n      {\n        \"id\": \"iterationitem:0\",\n        \"type\": \"iterationStartNode\",\n        \"parentId\": \"iteration:0\",\n        \"position\": {\n          \"x\": 40,\n          \"y\": 80\n        },\n        \"data\": {\n          \"label\": \"IterationItem\",\n          \"name\": \"iterationitem_0\",\n          \"form\": {\n            \"outputs\": {\n              \"index\": {\n                \"type\": \"integer\"\n              },\n              \"item\": {\n                \"type\": \"unknown\"\n              }\n            }\n          }\n        }\n      },\n      {\n        \"id\": \"agent:1\",\n        \"type\": \"agentNode\",\n        \"parentId\": \"iteration:0\",\n        \"position\": {\n          \"x\": 300,\n          \"y\": 80\n        },\n        \"data\": {\n          \"label\": \"Agent\",\n          \"name\": \"agent_1\",\n          \"form\": {\n            \"llm_id\": \"your-chat-model@provider\",\n            \"sys_prompt\": \"Write one short sentence about this sub-topic: {iterationitem:0@item}\",\n            \"prompts\": [\n              {\n                \"role\": \"user\",\n                \"content\": \"{iterationitem:0@item}\"\n              }\n            ],\n            \"max_tokens\": 128,\n            \"temperature\": 0.1,\n            \"top_p\": 0.3,\n            \"presence_penalty\": 0,\n            \"frequency_penalty\": 0,\n            \"max_retries\": 3,\n            \"delay_after_error\": 1,\n            \"max_rounds\": 1,\n            \"tools\": [],\n            \"mcp\": [],\n            \"cite\": false\n          }\n        }\n      },\n      {\n        \"id\": \"message:0\",\n        \"type\": \"messageNode\",\n        \"position\": {\n          \"x\": 990,\n          \"y\": 220\n        },\n        \"data\": {\n          \"label\": \"Message\",\n          \"name\": \"message_0\",\n          \"form\": {\n            \"content\": [\n              \"{iteration:0@reports}\"\n            ]\n          }\n        }\n      }\n    ],\n    \"edges\": [\n      {\n        \"id\": \"begin-agent:0\",\n        \"source\": \"begin\",\n        \"target\": \"agent:0\"\n      },\n      {\n        \"id\": \"agent:0-iteration:0\",\n        \"source\": \"agent:0\",\n        \"target\": \"iteration:0\"\n      },\n      {\n        \"id\": \"iterationitem:0-agent:1\",\n        \"source\": \"iterationitem:0\",\n        \"target\": \"agent:1\"\n      },\n      {\n        \"id\": \"agent:1-iterationitem:0\",\n        \"source\": \"agent:1\",\n        \"target\": \"iterationitem:0\"\n      },\n      {\n        \"id\": \"iteration:0-message:0\",\n        \"source\": \"iteration:0\",\n        \"target\": \"message:0\"\n      }\n    ]\n  }\n}\n\nFile v3.0.0:references/examples/agents/05-webhook-message.json\n\n{\n  \"components\": {\n    \"begin\": {\n      \"obj\": {\n        \"component_name\": \"Begin\",\n        \"params\": {\n          \"mode\": \"Webhook\",\n          \"prologue\": \"Webhook agent\",\n          \"methods\": [\n            \"POST\"\n          ],\n          \"content_types\": \"application/json\",\n          \"schema\": {\n            \"query\": {\n              \"type\": \"object\",\n              \"required\": [],\n              \"properties\": {}\n            },\n            \"headers\": {\n              \"type\": \"object\",\n              \"required\": [],\n              \"properties\": {}\n            },\n            \"body\": {\n              \"type\": \"object\",\n              \"required\": [\n                \"message\"\n              ],\n              \"properties\": {\n                \"message\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          },\n          \"security\": {\n            \"auth_type\": \"none\",\n            \"ip_whitelist\": [],\n            \"rate_limit\": {\n              \"limit\": 60,\n              \"per\": \"minute\"\n            },\n            \"max_body_size\": \"1MB\"\n          },\n          \"execution_mode\": \"Immediately\",\n          \"response\": {\n            \"status\": 200,\n            \"body_template\": \"{\\\"accepted\\\":true}\"\n          }\n        }\n      },\n      \"downstream\": [\n        \"message:0\"\n      ],\n      \"upstream\": []\n    },\n    \"message:0\": {\n      \"obj\": {\n        \"component_name\": \"Message\",\n        \"params\": {\n          \"content\": [\n            \"Webhook received: {begin@body.message}\"\n          ]\n        }\n      },\n      \"downstream\": [],\n      \"upstream\": [\n        \"begin\"\n      ]\n    }\n  },\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [\n      {\n        \"id\": \"begin\",\n        \"type\": \"beginNode\",\n        \"position\": {\n          \"x\": 50,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Begin\",\n          \"name\": \"begin\",\n          \"form\": {\n            \"mode\": \"Webhook\",\n            \"prologue\": \"Webhook agent\",\n            \"methods\": [\n              \"POST\"\n            ],\n            \"content_types\": \"application/json\",\n            \"schema\": {\n              \"query\": {\n                \"type\": \"object\",\n                \"required\": [],\n                \"properties\": {}\n              },\n              \"headers\": {\n                \"type\": \"object\",\n                \"required\": [],\n                \"properties\": {}\n              },\n              \"body\": {\n                \"type\": \"object\",\n                \"required\": [\n                  \"message\"\n                ],\n                \"properties\": {\n                  \"message\": {\n                    \"type\": \"string\"\n                  }\n                }\n              }\n            },\n            \"security\": {\n              \"auth_type\": \"none\",\n              \"ip_whitelist\": [],\n              \"rate_limit\": {\n                \"limit\": 60,\n                \"per\": \"minute\"\n              },\n              \"max_body_size\": \"1MB\"\n            },\n            \"execution_mode\": \"Immediately\",\n            \"response\": {\n              \"status\": 200,\n              \"body_template\": \"{\\\"accepted\\\":true}\"\n            }\n          }\n        }\n      },\n      {\n        \"id\": \"message:0\",\n        \"type\": \"messageNode\",\n        \"position\": {\n          \"x\": 360,\n          \"y\": 200\n        },\n        \"data\": {\n          \"label\": \"Message\",\n          \"name\": \"message_0\",\n          \"form\": {\n            \"content\": [\n              \"Webhook received: {begin@body.message}\"\n            ]\n          }\n        }\n      }\n    ],\n    \"edges\": [\n      {\n        \"id\": \"begin-message:0\",\n        \"source\": \"begin\",\n        \"target\": \"message:0\"\n      }\n    ]\n  }\n}\n\nFile v3.0.0:references/REFERENCE.md\n\n# Reporting RAGFlow results\n\nUse this reference when summarizing operational results. Match the user's requested format; keep raw `--json` for automation or when explicitly requested.\n\n- **Resources:** report the name, exact ID when needed for a subsequent action, and the affected dataset/document/session. Distinguish the returned page count from the server's total; do not present one page as a complete inventory.\n- **Retrieval:** report source filenames and relevant excerpts with server similarity scores. Preserve the 0–1 scale or explicitly label a percentage conversion. `chunks.length` is the returned count; `total` is the server total. Empty results do not prove the source lacks the information.\n- **Parsing:** preserve `UNSTART`, `RUNNING`, `CANCEL`, `DONE`, `FAIL`, or `SCHEDULE` as returned. A submitted task is not a completed parse. Report failures and timeouts with the affected IDs.\n- **Models:** include provider and instance, and use the returned `identifier` for follow-up operations. `configured` means present in the catalog, not a verified working connection.\n- **Files:** report saved path, MIME type, and size. Do not paste base64 file content into a normal user-facing response.\n- **Graphs:** distinguish total entities/relations from returned entities/relations; filtering or limits can make these counts differ.\n- **Chat and agents:** present the answer and actual returned citations. Retain session IDs for continuation. Do not invent references when none were returned.\n- **Errors:** report the failed operation, server code/message, relevant target, and a specific next step. Do not claim success after an error or conceal partial failures.\n- **Secrets and embeds:** omit API keys, provider credentials, token/beta values, and URLs or HTML containing `auth=` unless the user explicitly requests those values. Describe the chat/agent, mode, session, and whether embed setup succeeded.\n\nFile v3.0.0:references/TROUBLESHOOTING.md\n\n# Troubleshooting\n\n| Problem | Cause | Solution |\n|---------|-------|----------|\n| `system-health` fails | The configured server is unavailable or one of its dependencies reports unhealthy | Check `RAGFLOW_URL` and inspect the structured response with `--json`; use `list-datasets --page-size 1 --json` to test authentication separately |\n| `Unknown option for <command>: --...` | The option is misspelled or does not apply to that command | Run `node scripts/ragflow.js --help` and use the documented kebab-case option |\n| \"Model not authorized\" | Requested model is not configured for this tenant, or the model/factory name does not match | Verify the model name, factory suffix, and tenant model settings; use a configured model from `list-models` |\n| \"Embedding model identifier must follow `<model_name>@<provider>` format\" | `create-dataset --embedding-model` used only the model name | Use a full identifier from `list-models`, for example `text-embedding-v4@Tongyi-Qianwen` |\n| `AttributeError(\"'int' object has no attribute 'split'\")` from `create-chat` | A numeric model row ID from `list-models` was sent as `--llm-id` | Use `<model_name>@<provider>`, for example `qwen-turbo@Tongyi-Qianwen`, not the numeric `id` field |\n| \"Malformed JSON syntax\" | The request body is not valid JSON | Fix the JSON payload or file contents before retrying |\n| Uploaded document name looks like a task ID | The physical path passed to `--files` is a temporary/task-generated filename, and RAGFlow stores the multipart `filename` as document name | Use `--files <original-name>=<path>`; API users can pass `{ path, name }` |\n| \"Can't stop parsing\" | The document is already done or has not started yet | Only running documents can be stopped |\n| \"No DSL data in request\" | Agent creation omitted the DSL payload | Pass `--dsl` with a valid JSON object |\n| \"Invalid DSL JSON string.\" | The DSL payload is not valid JSON | Pass a JSON object or `@file.json` that can be normalized by the agent parser |\n| `KeyError('path')` from `create-agent-session` | Agent DSL is missing runtime fields required by RAGFlow Canvas | Include top-level `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`, and make sure every component-backed graph node has `data.name`; see `AGENT_GUIDE.md` |\n| Iteration agent creates successfully but fails at execution time | `items_ref` resolved to a non-list, often because the upstream `Agent` did not produce `structured.items` | Make the upstream `Agent` emit an object with an `items` array and point `Iteration.params.items_ref` at `agent:0@structured.items`; start from `references/examples/agents/04-iteration-agent.json` |\n| \"Dataset doesn't own parsed file\" | The dataset has no parsed documents yet | Upload files and start parsing before creating a chat assistant |\n| \"Chunk not found\" | Chunk ID does not exist or belongs to another document | Verify the chunk ID with `list-chunks` before `update-chunk` or `delete-chunks` |\n| `rm_chunk deleted chunks 0, expect 1` | The RAGFlow server accepted the chunk ID but document-store search/delete visibility lagged behind exact ID visibility | `delete-chunks` retries only after exact ID lookup confirms the chunk exists; with `--json`, consume `existing_chunk_ids` and `missing_chunk_ids`; tune with `RAGFLOW_DELETE_CHUNK_RETRIES` and `RAGFLOW_DELETE_CHUNK_RETRY_DELAY_MS`, or run `node scripts/repro-delete-chunks.js --confirm-destructive` for a clean diagnosis |\n| \"`content` is required\" | Empty content was submitted to chunk update or set | Provide non-empty content; omitting `--content` on the CLI keeps the existing chunk text |\n| `chat-session` returns Not Found | You are calling the login-session frontend route instead of the API-key SDK route | Use the current CLI or client, which posts to `/api/v1/chat/completions` with `chat_id` and `session_id` in the body |\n| `embed-code` or `embed-chat` returns Unauthorized | The embedded shared-site routes authenticate with the system token `beta`, not `RAGFLOW_API_KEY` | Let the CLI auto-create/reuse a token, or pass a valid `--beta` from `/api/v1/system/tokens` |\n| `embed-code` creates a new token unexpectedly | No existing system token had a `beta` value | This matches RAGFlow's embed UI behavior; use `list-system-tokens` to inspect current tokens |\n| `embed-chat` returns only the prologue or an empty answer | The embedded chatbot route was called without `session_id`; RAGFlow uses that first call to create the iframe session | Use the CLI `embed-chat` command, which bootstraps `session_id` automatically, or call `ensureEmbeddedChatSession()` before `embeddedChat()` in API code |\n| `list-models` returns Unauthorized | The `/api/v1/models` endpoint rejected the API key | Verify `RAGFLOW_API_KEY` is valid and has not expired |\n| `update-document` gets Method Not Allowed | The server does not match the v0.27.2 route shape expected by this skill | Use a v0.27.2-compatible server; document updates are sent with `PATCH` |\n| A list command fails with a `page_size` error | RAGFlow v0.27.2 caps `page_size` at 100 on list endpoints | The CLI clamps `--page-size` to 100 and warns; lower the value or page through results |\n| `Invalid URL` | `RAGFLOW_URL` is empty or malformed | Use a server root such as `http://localhost:9380`; bare hosts like `localhost:9380` are normalized to `http://...` |\n| Connection refused | `RAGFLOW_URL` is wrong or the server is down | Verify the URL and that the RAGFlow server is running |\n| API key exposed in logs or chat | The API key was shared or logged | Never share keys in chat; regenerate leaked keys and prefer `RAGFLOW_PROVIDER_API_KEY` or `--api-key-file` for provider credentials |\n| Security warning on ClawHub install | The skill requires `RAGFLOW_API_KEY` which grants access to your RAGFlow deployment | Use a least-privilege API key, use HTTPS in production, and review permissions before approving |\n| \"Connector authentication failed\" | The external service rejected the connector credentials or the endpoint is unreachable | Verify the API key, secret, and base URL in the connector configuration |\n| \"Invalid tag format\" | Document tags were submitted in an unsupported format (e.g. nested objects) | Use simple strings or arrays of strings for document tags |\n\nIn `--json` mode, command failures are emitted on stdout as `{ \"error\": { \"message\", \"raw_message\", \"code\", \"status\", \"command\" } }` and exit non-zero. `delete-chunks` may also include `existing_chunk_ids`, `missing_chunk_ids`, `retry_count`, `retries`, and `delete_chunk_diagnostics`.\n\n## v0.27.2 retrieval and parser changes\n\n- If retrieval rejects `rerank_candidates_count`, set `--rerank-candidates-count` to at least `--page × --top-n`. Without flags the server uses page 1, page size 30, and 64 candidates; page 3 at size 30 needs at least 90 candidates.\n- If `knn_num_candidates` is rejected, make it at least `knn_top_k` (1024 by default). Prefer `--knn-top-k` over deprecated `--top-k`.\n- Connector creation requires `name`, `source`, and `config`; `type` is not a substitute for `source`.\n- Dataset/document responses omit legacy `parser_config.graphrag` and `parser_config.raptor` entries. Missing keys do not prove that an indexing task failed; inspect `trace-graphrag` / `trace-raptor` and graph output.\n- Document structure graphs now include total and returned entity/relation counts. A limited or filtered graph can return fewer nodes than the totals.\n\nArchive v2.0.1: 17 files, 62426 bytes\n\nFiles: agents/openai.yaml (213b), lib/api.js (33649b), references/AGENT_GUIDE.md (12310b), references/API.md (21220b), references/COMMANDS.md (29395b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (1920b), references/TROUBLESHOOTING.md (7424b), scripts/ragflow.js (70340b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2124b), SKILL.md (9991b), _meta.json (136b)\n\nFile v2.0.1:SKILL.md\n\n---\nname: skill-for-ragflow\ndescription: Operate RAGFlow v0.27.2 deployments through a bundled Node CLI for everyday knowledge-base setup, document ingestion, parsing, retrieval, chat assistants, agents, GraphRAG, connectors, models, and diagnostics. Use when a request explicitly involves a RAGFlow server, dataset, document pipeline, or RAGFlow agent.\nmetadata:\n  openclaw:\n    requires:\n      bins:\n        - node\n      env:\n        - RAGFLOW_URL\n        - RAGFLOW_API_KEY\n    primaryEnv: RAGFLOW_API_KEY\n    homepage: https://github.com/LunarCache/ragflow-skill\n---\n\n# RAGFlow Skill\n\nOperate common RAGFlow v0.27.2 workflows through `node {baseDir}/scripts/ragflow.js <command> [options]`. Prefer `--json` when parsing or chaining results. Prioritize daily operations over exhaustive API coverage.\n\nThis package targets v0.27.2 and accepts only current API parameters. Use `--knn-top-k` for retrieval and `--session` for chat; no deprecated aliases or legacy streaming mode are supported.\n\n## Requirements\n\n- Set `RAGFLOW_URL` and `RAGFLOW_API_KEY` in the environment or this skill's `.env`.\n- Use Node.js to run bundled scripts.\n- Run `system-health --json` after first-time setup to verify service reachability and dependencies. Run `system-version --json` to identify the deployment version. Use `list-datasets --page-size 1 --json` to verify API-key authentication.\n\n## Security Notes\n\n- **Use HTTPS in production.** Production deployments should use `https://` for `RAGFLOW_URL` to protect the API key in transit. Local development (`http://localhost`) is acceptable for testing.\n- **Use a dedicated, rotatable API key for automation.** RAGFlow v0.27.2 API keys are tenant-scoped rather than permission-scoped.\n- **Protect your API key.** Never share `RAGFLOW_API_KEY` in chat messages or commit it to version control. Use environment variables or the skill's `.env` file.\n\n## Quick Command Reference\n\n| Scenario | Commands |\n|----------|----------|\n| **Knowledge base setup** | `create-dataset`, `list-datasets`, `get-dataset`, `update-dataset`, `delete-datasets` |\n| **Document ingestion** | `upload-documents`, `ingest-documents`, `list-documents`, `get-document`, `update-document`, `delete-documents`, `download-document`, `preview-document`, `metadata-summary`, `update-metadata` |\n| **Parsing & chunking** | `start-parsing`, `stop-parsing`, `wait-parsing`, `list-chunks`, `get-chunk`, `add-chunk`, `update-chunk`, `delete-chunks`, `get-document-graph`, `delete-document-graph` |\n| **Direct retrieval** | `retrieve` |\n| **Chat assistant** | `create-chat`, `list-chats`, `get-chat`, `update-chat`, `patch-chat`, `delete-chats` |\n| **Chat sessions** | `create-session`, `list-sessions`, `get-session`, `update-session`, `delete-sessions`, `chat`, `chat-session` |\n| **Agent** | `create-agent`, `list-agents`, `get-agent`, `update-agent`, `delete-agents` |\n| **Agent Tags** | `list-agent-tags`, `update-agent-tags` |\n| **Agent sessions** | `create-agent-session`, `list-agent-sessions`, `delete-agent-sessions`, `agent-chat` |\n| **Connector** | `list-connectors`, `create-connector`, `get-connector`, `update-connector`, `delete-connector` |\n| **RAPTOR** | `run-raptor`, `trace-raptor` |\n| **GraphRAG** | `get-knowledge-graph`, `delete-knowledge-graph`, `run-graphrag`, `trace-graphrag` |\n| **Embedded website access** | `list-system-tokens`, `create-system-token`, `delete-system-token`, `embed-code`, `embed-info`, `embed-chat`, `embed-agent-chat` |\n| **Model discovery** | `list-models`, `list-added-models`, `list-default-models`, `set-default-model` |\n| **Model providers** | `list-providers`, `get-provider`, `add-provider`, `delete-provider`, `list-provider-models`, `list-provider-instances`, `get-provider-instance`, `create-provider-instance`, `delete-provider-instances`, `verify-provider`, `list-instance-models`, `add-instance-model`, `set-model-status` |\n| **System** | `system-version`, `system-health`, `get-log-levels`, `set-log-level` |\n\n## Common Workflows\n\n### Full RAG pipeline (upload -> parse -> retrieve)\n\n1. `create-dataset --name \"My KB\" --chunk-method naive`\n2. `upload-documents --dataset <id> --files ./doc1.pdf ./doc2.txt`\n3. `start-parsing --dataset <id> --doc-ids <doc_id1> <doc_id2>`\n4. `wait-parsing --dataset <id> --doc-ids <doc_id1> <doc_id2>`\n5. `retrieve --question \"What is X?\" --datasets <id>`\n\n### Chat assistant with sessions\n\n1. `create-chat --name \"Q&A\" --datasets <id> --llm-id qwen-turbo@Tongyi-Qianwen`\n2. `create-session --chat <chat_id>`\n3. `chat-session --chat <chat_id> --session <session_id> --question \"Hello\"`\n\n### Agent workflow\n\n1. `create-agent --title \"Assistant\" --dsl @agent_dsl.json`\n2. `create-agent-session --agent <agent_id>`\n3. `agent-chat --agent <agent_id> --session <session_id> --question \"Hello\"`\n\n`agent-chat` streams by default. Use `--stream false` for one final JSON response.\n\n### Connector workflow\n\n1. `create-connector --config @connector.json`\n2. `list-connectors`\n3. `get-connector --id <id>`\n\n### Model provider workflow (v0.27.2)\n\n1. `list-providers --available` to see configurable providers\n2. `add-provider --name <provider>`\n3. Set `RAGFLOW_PROVIDER_API_KEY`, then run `create-provider-instance --name <provider> --instance <name>` (credentials live on an instance; a provider can have several)\n4. `add-instance-model --name <provider> --instance <name> --model-name <model> --model-type chat`\n5. `set-default-model --model-type chat --model-provider <provider> --model-instance <name> --model-name <model>`\n\nUse `verify-provider --name <provider>` with `RAGFLOW_PROVIDER_API_KEY` set, or pass `--api-key-file <path>`, to test a key without persisting an instance.\n\n### Indexing and retrieval\n\nRun `run-raptor --dataset <id>` then `trace-raptor --dataset <id>`, or the equivalent `run-graphrag` / `trace-graphrag` commands. Retrieval uses `--knn-top-k`; when paginating, set `--rerank-candidates-count` to cover `--page × --top-n`. Read the command reference for server defaults and filtering.\n\n### Embedded website access\n\n1. `embed-code --chat <chat_id> --type fullscreen` or `embed-code --agent <agent_id> --type widget`\n2. `embed-info --chat <chat_id>` or `embed-info --agent <agent_id>`\n3. `embed-chat --chat <chat_id> --question \"Hello\"` or `embed-agent-chat --agent <agent_id> --question \"Hello\"`\n\n`embed-chat` automatically creates the embedded chatbot session when `--session` is omitted. RAGFlow's shared-site route only creates a session and returns the prologue on the first no-session request, so the CLI bootstraps `session_id` first and then sends the real question.\n\n## Workflow Decision Guide\n\nThe first step in any RAGFlow operation is resolving the target resource ID. After that, choose the right path:\n\n1. **Authoring or debugging a custom agent DSL?** -> Read [references/AGENT_GUIDE.md](references/AGENT_GUIDE.md) - it is a self-contained guide to the current RAGFlow agent DSL schema and includes minimal examples.\n2. **Need CLI syntax or option details?** -> Read [references/COMMANDS.md](references/COMMANDS.md) - it's organized by workflow scenario with full option tables.\n3. **Editing client code or checking request/response shapes?** -> Read [references/API.md](references/API.md) - it has examples for supported `RagflowClient` workflows.\n4. **A command failed?** -> Read [references/TROUBLESHOOTING.md](references/TROUBLESHOOTING.md) - common errors with causes and fixes.\n5. **Formatting output for the user?** -> Read [references/REFERENCE.md](references/REFERENCE.md) - consistent response templates and status labels.\n\n## Key Constraints\n\n- **Confirm destructive scope.** Confirm the exact target before any `delete-*` command or before `update-metadata` deletes metadata or selects every document. Skip confirmation only when removing temporary resources created in the same requested workflow.\n- **Choose the ingestion path first.** For built-in chunking, upload documents, adjust their parser configuration when needed, then run `start-parsing`. For ingestion-pipeline datasets, use `ingest-documents` instead.\n- **Preserve source filenames.** When an attachment is stored under a temporary or task-generated path, upload it as `--files <original-name>=<path>` so RAGFlow retains the user-facing name.\n- **Resolve complete, stable inputs.** Discover resource IDs with the corresponding `list-*` or `get-*` command, and paginate beyond RAGFlow's 100-item list limit. Use the `identifier` from `list-models` (`<model>@<instance>@<provider>`, or `<model>@<provider>` for the default instance) for `--embedding-model` and `--llm-id`; treat numeric model row IDs as display data only.\n- **Preserve session-history intent.** Let `chat-session` append the latest user message by default. Use `--pass-all-history` only when replacing stored history.\n- **Protect operational secrets.** Keep `RAGFLOW_API_KEY`, provider keys, system tokens, beta values, and embed URLs containing `auth=` out of user-facing output. Supply provider credentials through `RAGFLOW_PROVIDER_API_KEY` or `--api-key-file`; reveal secret material only when the user explicitly requests copy-paste output.\n- **Use the correct public embed origin.** Pass `--origin` when the browser-facing RAGFlow URL differs from `RAGFLOW_URL`. Let the CLI reuse or create a beta token and bootstrap the embedded chat session.\n- **Start Agent DSL work from the guide.** Read [references/AGENT_GUIDE.md](references/AGENT_GUIDE.md) before authoring or debugging agents, and adapt its minimal examples instead of reconstructing the canvas schema from memory.\n\n## Output Format\n\nUse raw `--json` internally, then summarize the operational result. Preserve the server's parsing labels (`UNSTART`, `RUNNING`, `CANCEL`, `DONE`, `FAIL`) and similarity scores. Redact API keys, system tokens, beta values, and `auth=` query values unless the user explicitly requests copy-paste secret material. Read [references/REFERENCE.md](references/REFERENCE.md) only when a result needs a domain-specific response template.\n\nFile v2.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn71t9qydjdg0w265b8n777sp585m9xj\",\n  \"slug\": \"skill-for-ragflow\",\n  \"version\": \"2.0.1\",\n  \"publishedAt\": 1790302478739\n}\n\nFile v2.0.1:references/AGENT_GUIDE.md\n\n# RAGFlow Custom Agent Guide\n\nRead this file only when you need to author, debug, or review a RAGFlow Agent/Canvas DSL. For CLI syntax, read [COMMANDS.md](COMMANDS.md). For SDK request and response shapes, read [API.md](API.md). For failures and recovery steps, read [TROUBLESHOOTING.md](TROUBLESHOOTING.md).\n\nThis guide distills the current RAGFlow v0.27.2 agent behavior into practical schema rules, minimal examples, and failure patterns you can use directly.\n\n## Contents\n\n- [Quick choice](#quick-choice)\n- [Shortest path](#shortest-path)\n- [Current schema checklist](#current-schema-checklist)\n- [Components and graph must agree](#components-and-graph-must-agree)\n- [Variable rules](#variable-rules)\n- [Customize by node type](#customize-by-node-type)\n- [Runtime conclusions](#runtime-conclusions)\n- [Minimal example index](#minimal-example-index)\n- [Common failures](#common-failures)\n\n## Quick choice\n\n| Goal | Read first | Start from |\n|---|---|---|\n| Build the smallest conversational agent | [Shortest path](#shortest-path) | `references/examples/agents/01-conversational-message.json` |\n| Add knowledge-base retrieval | [Customize by node type](#customize-by-node-type) for `Retrieval` and `Agent` | `references/examples/agents/02-retrieval-message.json` or `03-tool-agent.json` |\n| Build a tool-using LLM agent | [Customize by node type](#customize-by-node-type) for `Agent` | `references/examples/agents/03-tool-agent.json` |\n| Build a loop or batch-processing agent | [Customize by node type](#customize-by-node-type) for `Iteration / IterationItem` | `references/examples/agents/04-iteration-agent.json` |\n| Build a webhook agent | [Customize by node type](#customize-by-node-type) for `Webhook` | `references/examples/agents/05-webhook-message.json` |\n| Debug `KeyError('path')`, broken variable resolution, or skipped nodes | [Current schema checklist](#current-schema-checklist) and [Common failures](#common-failures) | Compare against your DSL |\n\n## Shortest path\n\nDo not start from an empty JSON object.\n\n1. Pick the closest file from `references/examples/agents/`.\n2. Replace only deployment-specific values such as `llm_id`, `kb_ids`, tool credentials, and prompt text.\n3. Keep the current runtime fields intact: `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`.\n4. Create the agent, look it up by title, create a session, and send a question.\n\n```bash\nnode {baseDir}/scripts/ragflow.js create-agent \\\n  --title \"My Agent\" \\\n  --dsl @references/examples/agents/01-conversational-message.json \\\n  --json\n\nnode {baseDir}/scripts/ragflow.js list-agents --name \"My Agent\" --json\nnode {baseDir}/scripts/ragflow.js create-agent-session --agent <agent_id> --json\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\" --json\n```\n\n`create-agent` currently returns `true` on success, not the new agent id.\n\n## Current schema checklist\n\nWhen you hand-author a DSL, keep this checklist:\n\n- Top level includes `components`, `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`\n- `components` is the runtime structure and `graph` is the canvas structure; node ids must line up across both\n- Every `graph.nodes[]` entry includes `data.name`\n- `globals` explicitly keeps the system variables\n- Every referenced `component_id` actually exists\n- Loop flows define both `Iteration` and `IterationItem`\n- Tool-enabled agents place tools under `Agent.params.tools`\n\nRecommended skeleton:\n\n```json\n{\n  \"components\": {},\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [],\n    \"edges\": []\n  }\n}\n```\n\nAdditional constraints:\n\n- Keep `sys.date` even though runtime refreshes it\n- `env.*` values come from top-level `variables`\n- `component_id@output_name` values come from node outputs\n- Prefer the current schema instead of relying on server-side migration from old DSL formats\n\n## Components and graph must agree\n\nRAGFlow agent DSL is not just an execution graph and not just a canvas export. `components` and `graph` must both be valid and must describe the same flow.\n\n### `components`\n\nEvery component should at least look like this:\n\n```json\n{\n  \"begin\": {\n    \"obj\": {\n      \"component_name\": \"Begin\",\n      \"params\": {}\n    },\n    \"downstream\": [\"message:0\"],\n    \"upstream\": []\n  }\n}\n```\n\nKey fields:\n\n- `obj.component_name`: runtime component type\n- `obj.params`: runtime parameters\n- `downstream`: successor component ids\n- `upstream`: predecessor component ids\n- `parent_id`: needed only for nested nodes such as `IterationItem`\n\n### `graph.nodes`\n\nEvery graph node should at least keep these fields:\n\n```json\n{\n  \"id\": \"begin\",\n  \"type\": \"beginNode\",\n  \"position\": { \"x\": 50, \"y\": 200 },\n  \"data\": {\n    \"label\": \"Begin\",\n    \"name\": \"begin\",\n    \"form\": {\n      \"mode\": \"conversational\",\n      \"prologue\": \"Hi! I'm your assistant.\"\n    }\n  }\n}\n```\n\nKey constraints:\n\n- `graph.nodes[].id` matches the `components` key\n- `graph.nodes[].data.name` is required\n- `graph.nodes[].data.form` should stay aligned with `obj.params`\n\n### `graph.edges`\n\nEach edge `source` and `target` must reference real component ids. Updating only `components.downstream` or only `graph.edges` leaves the runtime and canvas out of sync.\n\n## Variable rules\n\nRuntime variable resolution mainly supports three classes:\n\n- System variables: `{sys.query}`, `{sys.user_id}`, `{sys.history}`\n- Environment variables: `{env.foo}`\n- Component outputs: `{retrieval:0@formalized_content}`, `{begin@body.message}`\n\nRules:\n\n- Variables without `@` are read from `globals`\n- Variables with `@` must use `component_id@output_name`\n- Dot-path access is supported, for example `{begin@body.message}` or `{agent:0@structured.items.0.title}`\n\nMost variable failures come from ids, output names, or top-level fields not lining up.\n\n## Customize by node type\n\n### Begin\n\n`Begin.params.mode` currently supports:\n\n- `conversational`\n- `task`\n- `Webhook`\n\n`Webhook` is not an alias for ordinary chat mode. It triggers a separate webhook route and request-validation path.\n\n### Message\n\n`Message` most often emits the final answer:\n\n```json\n{\n  \"content\": [\n    \"{agent:0@content}\"\n  ]\n}\n```\n\n`content` is an array. Runtime selects one template at random, and templates can contain variable references.\n\n### Retrieval\n\n`Retrieval` can be either a canvas node or a tool definition inside `Agent.params.tools`. Common inputs are:\n\n- `query`\n- `kb_ids`\n- `similarity_threshold`\n- `top_n`\n- `top_k`\n\nIf you want an explicit retrieval stage on the canvas, start from `02-retrieval-message.json`. If you want retrieval as an LLM tool, start from `03-tool-agent.json`.\nAs of v0.27.0, metadata filters are correctly reused across canvas executions even when node state is modified, fixing an issue where filters could be lost during iterative debugging.\n\n### Agent\n\n`Agent` is the tool-capable LLM node. In the current structure, tools live under `Agent.params.tools`:\n\n```json\n{\n  \"tools\": [\n    {\n      \"component_name\": \"Retrieval\",\n      \"id\": \"Retrieval:tool0\",\n      \"name\": \"Retrieval\",\n      \"params\": {}\n    }\n  ]\n}\n```\n\nDo not model tools here as separate top-level `Tool` nodes. For this skill, prefer the embedded structure shown in `03-tool-agent.json`.\n`Agent` nodes can emit structured JSON output directly into the `structured` field when a JSON schema is provided, allowing downstream nodes to access fields without manual string parsing.\n\n### Iteration / IterationItem\n\nLoops require at least:\n\n- one `Iteration`\n- one `IterationItem`\n- `IterationItem.parent_id` pointing to its `Iteration`\n- `Iteration.params.items_ref` pointing to the collection being iterated\n\nTwo practical constraints matter here:\n\n- `items_ref` must resolve to a real list at runtime\n- if the upstream value comes from an `Agent`, do not make the agent emit a top-level array schema directly; use an object schema such as `{\"items\": [\"...\"]}` and point `items_ref` at `agent:0@structured.items`\n\n`04-iteration-agent.json` uses that pattern because it works against the current backend implementation.\n\n### Webhook\n\nWhen `Begin.mode = \"Webhook\"`, the server reads these extra fields:\n\n### Browser\n\n`Browser` is a component type that enables AI-driven browser automation within agent workflows. It allows agents to navigate web pages, extract content, and interact with browser elements programmatically. Use it when the agent needs to access live web data or perform web-based tasks as part of its workflow.\n\nWhen `Begin.mode = \"Webhook\"`, the server reads these extra fields:\n\n- `methods`\n- `content_types`\n- `schema`\n- `security`\n- `execution_mode`\n- `response`\n\n`schema` should follow the current exported JSON-schema-style object:\n\n```json\n{\n  \"body\": {\n    \"type\": \"object\",\n    \"required\": [\"message\"],\n    \"properties\": {\n      \"message\": { \"type\": \"string\" }\n    }\n  }\n}\n```\n\nUse `05-webhook-message.json` as the minimal reference.\n\n## Runtime conclusions\n\nRead this section only when you need to explain why a DSL can be created but still fails at session creation or runtime.\n\n### Creation\n\n`create-agent` calls `POST /api/v1/agents`. The server normalizes the DSL, which means:\n\n- `--dsl` can be inline JSON\n- `--dsl` can also be `@agent.json`\n- old component names and old node types may be migrated, but migration should not be treated as the target schema\n\n### Session\n\n`create-agent-session` creates a new `Canvas` from the current agent DSL, resets runtime state, and stores the current DSL in the session. A session keeps more than chat messages; it also keeps runtime DSL state.\n\n### Run\n\n`agent-chat` calls `POST /api/v1/agents/chat/completions` with `agent_id` in the body. Runtime updates:\n\n- `sys.query`\n- `history`\n- `sys.history`\n- `sys.conversation_turns`\n- `retrieval`\n\nThat is why removing these runtime-looking top-level fields can still let agent creation succeed while session creation or execution later fails.\n\n## Minimal example index\n\nAll examples live in `references/examples/agents/` and can be used directly with `--dsl @...`:\n\n| File | Best for | Usually replace |\n|---|---|---|\n| `01-conversational-message.json` | Smallest conversational agent, `Begin -> Message` | `prologue`, output template |\n| `02-retrieval-message.json` | Explicit retrieval chain, `Begin -> Retrieval -> Message` | `kb_ids`, retrieval thresholds, output template |\n| `03-tool-agent.json` | Tool-using LLM agent, `Begin -> Agent -> Message` | `llm_id`, `tools`, prompt |\n| `04-iteration-agent.json` | Loop or batch-processing agent | `items_ref`, loop-body prompt, aggregate output |\n| `05-webhook-message.json` | Webhook agent, `Begin(Webhook) -> Message` | `schema`, `security`, response definition |\n\nThese examples are structurally minimal, not production-minimal. Replace `llm_id`, `kb_ids`, API keys, webhook security settings, and any other deployment-specific values with real ones from your environment.\n\n## Common failures\n\n| Problem | Cause |\n|---|---|\n| `KeyError('path')` or session creation failure | Top-level runtime fields are incomplete |\n| Agent creates successfully but runtime cannot resolve variables | `graph.nodes[].id`, `components` keys, and variable references do not line up |\n| Logs or debugging output lose component names | `graph.nodes[].data.name` is missing |\n| Agent appears to have tools but never calls them | Tools were not written into `Agent.params.tools` |\n| Webhook agent creates successfully but endpoint behavior is broken | `Begin.mode`, `schema`, `security`, or `response` does not match the current implementation |\n| Iteration agent creates successfully but crashes at execution time | `items_ref` resolved to `None` or a non-list, often because the upstream `Agent` did not produce a real `structured.items` array |\n| Old DSL imports but behaves strangely | The server migrated it, but the final structure was not rewritten to the current schema |\n### v0.27.2 validation notes\n\nInteger DSL parameters must be JSON integers: fractional values such as `1.5` and booleans are rejected for positive/nonnegative-integer fields. Template references accept `{node@output}` or `{{node@output}}`; keep braces balanced.\n\nFile v2.0.1:references/API.md\n\n# Programmatic API and Configuration\n\n## Table of Contents\n\n- [Setup](#setup)\n- [Dataset](#dataset)\n- [Document](#document)\n- [Document Download](#document-download)\n- [Parsing](#parsing)\n- [Chunk](#chunk)\n- [Retrieval](#retrieval)\n- [Metadata](#metadata)\n- [Connector](#connector)\n- [RAPTOR](#raptor)\n- [GraphRAG](#graphrag)\n- [Chat Assistant](#chat-assistant)\n- [Session](#session)\n- [Chat Conversation](#chat-conversation)\n- [Agent](#agent)\n- [Agent Tags](#agent-tags)\n- [Agent Session](#agent-session)\n- [Agent Chat](#agent-chat)\n- [Embedded Website Access](#embedded-website-access)\n- [LLM Models](#llm-models)\n- [System](#system)\n- [Utility](#utility)\n- [Configuration](#configuration)\n\n## Setup\n\n```javascript\nconst { createClient } = require(\"{baseDir}/lib/api.js\");\nconst client = createClient();\n```\n\n`createClient()` reads `RAGFLOW_URL` and `RAGFLOW_API_KEY` from the environment and then fills missing values from the bundled `.env` file. Existing environment variables take precedence. See [Configuration](#configuration) below.\n\n## Dataset\n\n```javascript\n// List datasets (supports pagination: page, page_size, id, name)\nconst datasets = await client.listDatasets({ page: 1, page_size: 10 });\n\n// Get a single dataset by ID (enriched with total_size and connectors)\nconst dataset = await client.getDataset(\"<dataset_id>\");\n// Returns: { id: \"...\", name: \"...\", total_size: 1024, connectors: [...], ... }\n\n// Create a dataset\nconst dataset = await client.createDataset({\n  name: \"Tech Docs\",\n  chunk_method: \"naive\",\n});\n\n// Update a dataset\nawait client.updateDataset(\"<dataset_id>\", { name: \"New Name\" });\n\n// Delete datasets by IDs\nawait client.deleteDatasets([\"<id1>\", \"<id2>\"]);\n```\n\n## Document\n\n```javascript\n// Upload documents\nawait client.uploadDocuments(\"<dataset_id>\", [\"./report.pdf\", \"./notes.txt\"]);\n\n// Override display names when paths are temporary/task IDs\nawait client.uploadDocuments(\"<dataset_id>\", [\n  { path: \"./tmp/task-output\", name: \"report.pdf\" },\n]);\n\n// List documents (supports page, page_size, id, name, orderby, desc, keywords, suffix, types, run, metadata, metadata_condition, return_empty_metadata)\nconst docs = await client.listDocuments(\"<dataset_id>\");\n\n// Get a single document by ID\nconst doc = await client.getDocument(\"<dataset_id>\", \"<doc_id>\");\n\n// Update a document\nawait client.updateDocument(\"<dataset_id>\", \"<doc_id>\", {\n  name: \"Renamed\",\n  parser_config: { pages: [[1, 2]] },\n  chunk_method: \"knowledge_graph\",\n  enabled: 1,\n  meta_fields: { author: \"Alice\" },\n});\n\n// Delete documents by IDs\nawait client.deleteDocuments(\"<dataset_id>\", [\"<doc_id1>\", \"<doc_id2>\"]);\n```\n\nRAGFlow v0.27.2 defines document updates as `PATCH /api/v1/datasets/{dataset_id}/documents/{document_id}`. `updateDocument()` sends that request directly.\n\nYou can also filter documents by metadata:\n\n```javascript\nconst docs = await client.listDocuments(\"<dataset_id>\", {\n  metadata_condition: JSON.stringify({\n    logic: \"and\",\n    conditions: [{ name: \"status\", comparison_operator: \"=\", value: \"published\" }],\n  }),\n});\n```\n\nYou can also summarize metadata across documents:\n\n```javascript\nconst summary = await client.metadataSummary(\"<dataset_id>\", [\"<doc_id1>\", \"<doc_id2>\"]);\n// Returns: { summary: [...] }\n```\n\n## Document Download\n\n```javascript\n// Download via dataset\nconst doc = await client.downloadDocument(datasetId, documentId);\n\n// Download by document ID\nconst doc = await client.downloadDocumentById(documentId);\n\n// Preview a document inline (v0.27.2)\nconst preview = await client.previewDocument(documentId);\n```\n\nDownloads/previews are normalized from binary HTTP responses into `{ content, encoding: \"base64\", name, content_type, size }`. Decode with `Buffer.from(doc.content, \"base64\")`; `content` is not plain text or a remote URL. JSON API errors and HTTP failures still reject the request.\n\n## Parsing\n\n```javascript\n// Start parsing (returns immediately)\nawait client.startParsing(\"<dataset_id>\", [\"<doc_id1>\"]);\n\n// Stop parsing\nawait client.stopParsing(\"<dataset_id>\", [\"<doc_id1>\"]);\n\n// Start/rerun ingestion for ingestion-pipeline datasets\nawait client.ingestDocuments([\"<doc_id1>\"], { run: \"1\", delete: true });\n\n// Cancel ingestion for ingestion-pipeline datasets\nawait client.ingestDocuments([\"<doc_id1>\"], { run: \"2\" });\n\n// Wait for parsing to complete (polls until DONE or FAIL)\n// Documents stuck in CANCEL keep polling until timeout.\nconst results = await client.waitForParsing(\"<dataset_id>\", [\"<doc_id1>\"], {\n  interval: 3000,   // poll interval in ms (default: 3000)\n  maxWait: 120000,  // max wait in ms (default: 120000)\n});\n```\n\n## Chunk\n\n```javascript\n// List chunks (supports pagination: page, page_size, keywords)\nconst chunks = await client.listChunks(\"<dataset_id>\", \"<doc_id>\");\n\n// Exact chunk lookup by ID\nconst chunk = await client.getChunk(\"<dataset_id>\", \"<doc_id>\", \"<chunk_id>\");\n\n// Add a chunk\nawait client.addChunk(\"<dataset_id>\", \"<doc_id>\", {\n  content: \"Custom chunk text\",\n  important_keywords: [\"keyword1\", \"keyword2\"],\n});\n\n// Update a chunk\nawait client.updateChunk(\"<dataset_id>\", \"<doc_id>\", \"<chunk_id>\", {\n  content: \"Updated content\",\n  important_keywords: [\"new_keyword\"],\n});\n\n// Delete chunks by IDs\nawait client.deleteChunks(\"<dataset_id>\", \"<doc_id>\", [\"<chunk_id1>\"]);\n\n// Inspect or delete the document structure graph\nconst graph = await client.getDocumentStructureGraph(\"<dataset_id>\", \"<doc_id>\");\nawait client.deleteDocumentStructureGraph(\"<dataset_id>\", \"<doc_id>\");\n```\n\n`updateChunk()` uses `PATCH /api/v1/datasets/{dataset_id}/documents/{document_id}/chunks/{chunk_id}`. `ingestDocuments()` is for ingestion-pipeline datasets; use `startParsing()`/`stopParsing()` for the built-in chunking pipeline.\n\n`deleteChunks()` retries the transient `rm_chunk deleted chunks 0, expect N` response only after `getChunk()` confirms the target chunk still exists. This distinguishes document-store refresh delay from a genuinely missing chunk. Override with:\n\n```javascript\nawait client.deleteChunks(\"<dataset_id>\", \"<doc_id>\", [\"<chunk_id1>\"], {\n  maxRetries: 0,\n  retryDelay: 1000,\n});\n```\n\nWhen the CLI is run with `--json`, `delete-chunks` wraps the server result with diagnostic fields that pipelines can consume directly:\n\n```json\n{\n  \"result\": {},\n  \"requested_chunk_ids\": [\"<chunk_id1>\"],\n  \"existing_chunk_ids\": [\"<chunk_id1>\"],\n  \"missing_chunk_ids\": [],\n  \"visibility_checked\": true,\n  \"retry_count\": 1,\n  \"retries\": [\n    {\n      \"attempt\": 0,\n      \"next_attempt\": 2,\n      \"max_retries\": 3,\n      \"existing_chunk_ids\": [\"<chunk_id1>\"],\n      \"missing_chunk_ids\": []\n    }\n  ]\n}\n```\n\nOn a final delete visibility failure, the CLI exits non-zero and emits JSON with `error`, `requested_chunk_ids`, `existing_chunk_ids`, `missing_chunk_ids`, `retry_count`, `retries`, and `delete_chunk_diagnostics`.\n\nAll CLI command failures in `--json` mode use the same top-level error envelope:\n\n```json\n{\n  \"error\": {\n    \"message\": \"API Error: Unauthorized\",\n    \"raw_message\": \"Unauthorized\",\n    \"code\": 401,\n    \"status\": 401,\n    \"command\": \"list-models\"\n  }\n}\n```\n\nCommand-specific diagnostics, such as delete chunk visibility checks, are added as extra top-level fields alongside `error`.\n\n## Retrieval\n\n```javascript\nconst results = await client.retrieve({\n  question: \"What is deep learning?\",\n  dataset_ids: [\"<dataset_id>\"],\n  similarity_threshold: 0.3,\n  page_size: 5,\n  knn_top_k: 1024,\n  knn_num_candidates: 2048,\n  rerank_candidates_count: 64,\n  highlight: true,\n  include_knowledge_compilation: false,\n  vector_similarity_weight: 0.7,\n  keyword: true,\n  use_kg: false,\n  rerank_id: \"<rerank_model_id>\",\n});\n```\n\n`retrieve()` forwards the payload unchanged. Prefer `knn_top_k` over the deprecated `top_k`; `knn_num_candidates` must be at least `knn_top_k`. Set `rerank_candidates_count >= page * page_size` (defaults: 64, 1, 30). `document_ids` and `metadata_condition` filters intersect. `include_knowledge_compilation: false` excludes compiled chunks. The response is `{ chunks, total, doc_aggs }`.\n\n## Metadata\n\n```javascript\n// Batch-update or delete metadata for selected documents.\nawait client.updateMetadata(\"<dataset_id>\", {\n  selector: { document_ids: [\"<doc_id>\"] },\n  updates: [{ key: \"status\", value: \"reviewed\" }],\n});\n```\n\n## Connector\n\nConnectors are tenant-scoped (not dataset-scoped). The client calls the tenant-level routes.\n\n```javascript\n// List connectors (tenant scope)\nconst connectors = await client.listConnectors();\n\n// Create connector\nconst connector = await client.createConnector({\n  name: \"Documentation sitemap\",\n  source: \"sitemap\",\n  config: { sitemap_url: \"https://example.com/sitemap.xml\" }\n});\n\n// Get, update, delete connector\nconst conn = await client.getConnector(connectorId);\nawait client.updateConnector(connectorId, { refresh_freq: 10 });\nawait client.deleteConnector(connectorId);\n```\n\n## RAPTOR\n\n```javascript\n// Start RAPTOR processing\nconst task = await client.runRaptor(datasetId);\n\n// Check progress\nconst progress = await client.traceRaptor(datasetId);\n```\n\n## GraphRAG\n\n```javascript\nconst graph = await client.getKnowledgeGraph(datasetId);\nawait client.runGraphRag(datasetId);\nconst progress = await client.traceGraphRag(datasetId);\nawait client.deleteKnowledgeGraph(datasetId);\n```\n\n## Chat Assistant\n\n```javascript\n// List chat assistants (supports pagination)\nconst chats = await client.listChatAssistants({ page: 1, page_size: 10 });\n\n// Get a single chat assistant by ID\nconst chat = await client.getChatAssistant(\"<chat_id>\");\n\n// Create a chat assistant\nconst chat = await client.createChatAssistant({\n  name: \"Tech Q&A\",\n  dataset_ids: [\"<dataset_id>\"],\n  llm_id: \"qwen-turbo@Tongyi-Qianwen\",\n  prompt_config: { system: \"You are a helpful assistant.\" },\n  similarity_threshold: 0.3,\n  top_n: 5,\n});\n\n// Update a chat assistant\nawait client.updateChatAssistant(\"<chat_id>\", { name: \"New Name\" });\n\n// Patch a chat assistant\nawait client.patchChatAssistant(\"<chat_id>\", { prompt_config: { system: \"Use the dataset\" } });\n\n// Delete chat assistants by IDs\nawait client.deleteChatAssistants([\"<chat_id1>\", \"<chat_id2>\"]);\n```\n\n## Session\n\n```javascript\n// List sessions for a chat assistant\nconst sessions = await client.listSessions(\"<chat_id>\", { page: 1 });\n\n// Create a session\nconst session = await client.createSession(\"<chat_id>\", { name: \"Q&A Session\" });\n\n// Inspect or rename a session\nconst current = await client.getSession(\"<chat_id>\", \"<session_id>\");\nawait client.updateSession(\"<chat_id>\", \"<session_id>\", { name: \"Reviewed Q&A\" });\n\n// Delete sessions by IDs\nawait client.deleteSessions(\"<chat_id>\", [\"<session_id1>\"]);\n```\n\n## Chat Conversation\n\n```javascript\n// Chat with an assistant (streaming SSE, returns final answer + references)\nconst answer = await client.chat(\"<chat_id>\", \"<session_id>\", \"What is RAG?\");\n// Returns: { answer: \"...\", reference: { ... } }\n\n// Chat with a session (messages payload)\nconst sessionAnswer = await client.chatSession(\"<chat_id>\", \"<session_id>\", {\n  question: \"Summarize the policy.\",\n});\n\n// Convenience form: the last user message becomes `question`\nconst sessionAnswerFromMessages = await client.chatSession(\"<chat_id>\", \"<session_id>\", {\n  messages: [\n    { role: \"system\", content: \"Follow the dataset.\" },\n    { role: \"user\", content: \"Summarize the policy.\" },\n  ],\n});\n```\n\n`chatSession()` uses `POST /api/v1/chat/completions` with `chat_id` and `session_id` in the JSON body. Use `session_id` for session identity. By default, only the latest\n\nArchive v2.0.0: 18 files, 65954 bytes\n\nFiles: agents/openai.yaml (213b), lib/api.js (33649b), references/AGENT_GUIDE.md (12384b), references/API.md (21220b), references/COMMANDS.md (29395b), references/COMPATIBILITY.md (8242b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (1920b), references/TROUBLESHOOTING.md (7424b), scripts/ragflow.js (70340b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2123b), SKILL.md (10119b), _meta.json (136b)\n\nArchive v1.8.0: 17 files, 62437 bytes\n\nFiles: agents/openai.yaml (213b), lib/api.js (33094b), references/AGENT_GUIDE.md (12376b), references/API.md (21035b), references/COMMANDS.md (28213b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (6354b), references/TROUBLESHOOTING.md (6576b), scripts/ragflow.js (73012b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2611b), SKILL.md (9903b), _meta.json (136b)\n\nArchive v1.7.0: 17 files, 61957 bytes\n\nFiles: agents/openai.yaml (213b), lib/api.js (32732b), references/AGENT_GUIDE.md (12376b), references/API.md (20414b), references/COMMANDS.md (27870b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (6354b), references/TROUBLESHOOTING.md (6571b), scripts/ragflow.js (71526b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2791b), SKILL.md (9886b), _meta.json (136b)\n\nArchive v1.6.0: 17 files, 61122 bytes\n\nFiles: agents/openai.yaml (453b), lib/api.js (31477b), references/AGENT_GUIDE.md (12376b), references/API.md (19407b), references/COMMANDS.md (26796b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (6149b), references/TROUBLESHOOTING.md (6068b), scripts/ragflow.js (65526b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2877b), SKILL.md (14692b), _meta.json (136b)\n\nArchive v1.5.0: 17 files, 59598 bytes\n\nFiles: agents/openai.yaml (449b), lib/api.js (29928b), references/AGENT_GUIDE.md (12047b), references/API.md (17934b), references/COMMANDS.md (25020b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (6149b), references/TROUBLESHOOTING.md (6036b), scripts/ragflow.js (61854b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2685b), SKILL.md (14260b), _meta.json (136b)\n\nArchive v1.4.0: 17 files, 55033 bytes\n\nFiles: agents/openai.yaml (418b), lib/api.js (26836b), references/AGENT_GUIDE.md (12084b), references/API.md (15030b), references/COMMANDS.md (21733b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (6149b), references/TROUBLESHOOTING.md (5837b), scripts/ragflow.js (52203b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2820b), SKILL.md (12122b), _meta.json (136b)\n\nArchive v1.3.0: 17 files, 53937 bytes\n\nFiles: agents/openai.yaml (418b), lib/api.js (26570b), references/AGENT_GUIDE.md (11676b), references/API.md (14680b), references/COMMANDS.md (21013b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (6149b), references/TROUBLESHOOTING.md (5837b), scripts/ragflow.js (51248b), scripts/repro-delete-chunks.js (6566b), skill-card.md (2456b), SKILL.md (11749b), _meta.json (136b)\n\nArchive v1.2.6: 16 files, 50259 bytes\n\nFiles: agents/openai.yaml (418b), lib/api.js (24993b), references/AGENT_GUIDE.md (11281b), references/API.md (13398b), references/COMMANDS.md (19912b), references/examples/agents/01-conversational-message.json (1715b), references/examples/agents/02-retrieval-message.json (3204b), references/examples/agents/03-tool-agent.json (5224b), references/examples/agents/04-iteration-agent.json (8352b), references/examples/agents/05-webhook-message.json (3839b), references/REFERENCE.md (5040b), references/TROUBLESHOOTING.md (5474b), scripts/ragflow.js (46532b), scripts/repro-delete-chunks.js (6566b), SKILL.md (10896b), _meta.json (136b)","readmeExcerpt":"Skill: RAGFlow Skill Owner: lunarcache Summary: Manage everyday RAGFlow datasets, retrieval, chat, and agents. Tags: latest:3.0.0 Version history: v3.0.0 | 2026-09-25T02:38:34.249Z | user Require explicit authorization flags for destructive requests; harden embedded HTML and widget messages; validate multipart upload names. RAGFlow v0.27.2 APIs only. v2.0.1 | 2026-09-25T02:14:38.739Z | user Remove compatibility analy","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"node {baseDir}/scripts/ragflow.js create-agent \\\n  --title \"My Agent\" \\\n  --dsl @references/examples/agents/01-conversational-message.json \\\n  --json\n\nnode {baseDir}/scripts/ragflow.js list-agents --name \"My Agent\" --json\nnode {baseDir}/scripts/ragflow.js create-agent-session --agent <agent_id> --json\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\" --json"},{"language":"json","snippet":"{\n  \"components\": {},\n  \"history\": [],\n  \"path\": [],\n  \"retrieval\": [],\n  \"variables\": {},\n  \"globals\": {\n    \"sys.query\": \"\",\n    \"sys.user_id\": \"\",\n    \"sys.conversation_turns\": 0,\n    \"sys.files\": [],\n    \"sys.history\": [],\n    \"sys.date\": \"\"\n  },\n  \"graph\": {\n    \"nodes\": [],\n    \"edges\": []\n  }\n}"},{"language":"json","snippet":"{\n  \"begin\": {\n    \"obj\": {\n      \"component_name\": \"Begin\",\n      \"params\": {}\n    },\n    \"downstream\": [\"message:0\"],\n    \"upstream\": []\n  }\n}"},{"language":"json","snippet":"{\n  \"id\": \"begin\",\n  \"type\": \"beginNode\",\n  \"position\": { \"x\": 50, \"y\": 200 },\n  \"data\": {\n    \"label\": \"Begin\",\n    \"name\": \"begin\",\n    \"form\": {\n      \"mode\": \"conversational\",\n      \"prologue\": \"Hi! I'm your assistant.\"\n    }\n  }\n}"},{"language":"json","snippet":"{\n  \"content\": [\n    \"{agent:0@content}\"\n  ]\n}"},{"language":"json","snippet":"{\n  \"tools\": [\n    {\n      \"component_name\": \"Retrieval\",\n      \"id\": \"Retrieval:tool0\",\n      \"name\": \"Retrieval\",\n      \"params\": {}\n    }\n  ]\n}"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: skill-for-ragflow\ndescription: Operate RAGFlow v0.27.2 deployments through a bundled Node CLI for everyday knowledge-base setup, document ingestion, parsing, retrieval, chat assistants, agents, GraphRAG, connectors, models, and diagnostics. Use when a request explicitly involves a RAGFlow server, dataset, document pipeline, or RAGFlow agent.\nmetadata:\n  openclaw:\n    requires:\n      bins:\n        - node\n      env:\n        - RAGFLOW_URL\n        - RAGFLOW_API_KEY\n    primaryEnv: RAGFLOW_API_KEY\n    homepage: https://github.com/LunarCache/ragflow-skill\n---\n\n# RAGFlow Skill\n\nOperate common RAGFlow v0.27.2 workflows through `node {baseDir}/scripts/ragflow.js <command> [options]`. Prefer `--json` when parsing or chaining results. Prioritize daily operations over exhaustive API coverage.\n\nThis package targets v0.27.2 and accepts only current API parameters. Use `--knn-top-k` for retrieval and `--session` for chat; no deprecated aliases or legacy streaming mode are supported.\n\n## Requirements\n\n- Set `RAGFLOW_URL` and `RAGFLOW_API_KEY` in the environment or this skill's `.env`.\n- Use Node.js to run bundled scripts.\n- Run `system-health --json` after first-time setup to verify service reachability and dependencies. Run `system-version --json` to identify the deployment version. Use `list-datasets --page-size 1 --json` to verify API-key authentication.\n\n## Security Notes\n\n- **Use HTTPS in production.** Production deployments should use `https://` for `RAGFLOW_URL` to protect the API key in transit. Local development (`http://localhost`) is acceptable for testing.\n- **Use a dedicated, rotatable API key for automation.** RAGFlow v0.27.2 API keys are tenant-scoped rather than permission-scoped.\n- **Protect your API key.** Never share `RAGFLOW_API_KEY` in chat messages or commit it to version control. Use environment variables or the skill's `.env` file.\n\n## Quick Command Reference\n\n| Scenario | Commands |\n|----------|----------|\n| **Knowledge base setup** | `create-dataset`, `list-datasets`, `get-dataset`, `update-dataset`, `delete-datasets` |\n| **Document ingestion** | `upload-documents`, `ingest-documents`, `list-documents`, `get-document`, `update-document`, `delete-documents`, `download-document`, `preview-document`, `metadata-summary`, `update-metadata` |\n| **Parsing & chunking** | `start-parsing`, `stop-parsing`, `wait-parsing`, `list-chunks`, `get-chunk`, `add-chunk`, `update-chunk`, `delete-chunks`, `get-document-graph`, `delete-document-graph` |\n| **Direct retrieval** | `retrieve` |\n| **Chat assistant** | `create-chat`, `list-chats`, `get-chat`, `update-chat`, `patch-chat`, `delete-chats` |\n| **Chat sessions** | `create-session`, `list-sessions`, `get-session`, `update-session`, `delete-sessions`, `chat`, `chat-session` |\n| **Agent** | `create-agent`, `list-agents`, `get-agent`, `update-agent`, `delete-agents` |\n| **Agent Tags** | `list-agent-tags`, `update-agent-tags` |\n| **Agent sessions** | `create-agent-session`, `list-agent-sessions`, `"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn71t9qydjdg0w265b8n777sp585m9xj\",\n  \"slug\": \"skill-for-ragflow\",\n  \"version\": \"3.0.0\",\n  \"publishedAt\": 1790303914249\n}"},{"path":"references/AGENT_GUIDE.md","content":"# RAGFlow Custom Agent Guide\n\nRead this file only when you need to author, debug, or review a RAGFlow Agent/Canvas DSL. For CLI syntax, read [COMMANDS.md](COMMANDS.md). For SDK request and response shapes, read [API.md](API.md). For failures and recovery steps, read [TROUBLESHOOTING.md](TROUBLESHOOTING.md).\n\nThis guide distills the current RAGFlow v0.27.2 agent behavior into practical schema rules, minimal examples, and failure patterns you can use directly.\n\n## Contents\n\n- [Quick choice](#quick-choice)\n- [Shortest path](#shortest-path)\n- [Current schema checklist](#current-schema-checklist)\n- [Components and graph must agree](#components-and-graph-must-agree)\n- [Variable rules](#variable-rules)\n- [Customize by node type](#customize-by-node-type)\n- [Runtime conclusions](#runtime-conclusions)\n- [Minimal example index](#minimal-example-index)\n- [Common failures](#common-failures)\n\n## Quick choice\n\n| Goal | Read first | Start from |\n|---|---|---|\n| Build the smallest conversational agent | [Shortest path](#shortest-path) | `references/examples/agents/01-conversational-message.json` |\n| Add knowledge-base retrieval | [Customize by node type](#customize-by-node-type) for `Retrieval` and `Agent` | `references/examples/agents/02-retrieval-message.json` or `03-tool-agent.json` |\n| Build a tool-using LLM agent | [Customize by node type](#customize-by-node-type) for `Agent` | `references/examples/agents/03-tool-agent.json` |\n| Build a loop or batch-processing agent | [Customize by node type](#customize-by-node-type) for `Iteration / IterationItem` | `references/examples/agents/04-iteration-agent.json` |\n| Build a webhook agent | [Customize by node type](#customize-by-node-type) for `Webhook` | `references/examples/agents/05-webhook-message.json` |\n| Debug `KeyError('path')`, broken variable resolution, or skipped nodes | [Current schema checklist](#current-schema-checklist) and [Common failures](#common-failures) | Compare against your DSL |\n\n## Shortest path\n\nDo not start from an empty JSON object.\n\n1. Pick the closest file from `references/examples/agents/`.\n2. Replace only deployment-specific values such as `llm_id`, `kb_ids`, tool credentials, and prompt text.\n3. Keep the current runtime fields intact: `history`, `path`, `retrieval`, `variables`, `globals`, and `graph`.\n4. Create the agent, look it up by title, create a session, and send a question.\n\n```bash\nnode {baseDir}/scripts/ragflow.js create-agent \\\n  --title \"My Agent\" \\\n  --dsl @references/examples/agents/01-conversational-message.json \\\n  --json\n\nnode {baseDir}/scripts/ragflow.js list-agents --name \"My Agent\" --json\nnode {baseDir}/scripts/ragflow.js create-agent-session --agent <agent_id> --json\nnode {baseDir}/scripts/ragflow.js agent-chat --agent <agent_id> --session <session_id> --question \"Hello\" --json\n```\n\n`create-agent` currently returns `true` on success, not the new agent id.\n\n## Current schema checklist\n\nWhen you hand-author a DSL, keep this checklist:\n\n- Top level includes `componen"},{"path":"references/API.md","content":"# Programmatic API and Configuration\n\n## Table of Contents\n\n- [Setup](#setup)\n- [Dataset](#dataset)\n- [Document](#document)\n- [Document Download](#document-download)\n- [Parsing](#parsing)\n- [Chunk](#chunk)\n- [Retrieval](#retrieval)\n- [Metadata](#metadata)\n- [Connector](#connector)\n- [RAPTOR](#raptor)\n- [GraphRAG](#graphrag)\n- [Chat Assistant](#chat-assistant)\n- [Session](#session)\n- [Chat Conversation](#chat-conversation)\n- [Agent](#agent)\n- [Agent Tags](#agent-tags)\n- [Agent Session](#agent-session)\n- [Agent Chat](#agent-chat)\n- [Embedded Website Access](#embedded-website-access)\n- [LLM Models](#llm-models)\n- [System](#system)\n- [Utility](#utility)\n- [Configuration](#configuration)\n\n## Setup\n\n```javascript\nconst { createClient } = require(\"{baseDir}/lib/api.js\");\nconst client = createClient();\n```\n\n`createClient()` reads `RAGFLOW_URL` and `RAGFLOW_API_KEY` from the environment and then fills missing values from the bundled `.env` file. Existing environment variables take precedence. See [Configuration](#configuration) below.\n\nDestructive requests fail with `CONFIRMATION_REQUIRED` before network access by default. After verifying authorization and target scope, create a dedicated client with `const destructiveClient = createClient({ allowDestructive: true });` for deletion, metadata removal or unscoped metadata updates, and ingestion with `delete: true`. Use that client for the deletion examples below; ordinary clients remain suitable for reads and scoped updates.\n\n## Dataset\n\n```javascript\n// List datasets (supports pagination: page, page_size, id, name)\nconst datasets = await client.listDatasets({ page: 1, page_size: 10 });\n\n// Get a single dataset by ID (enriched with total_size and connectors)\nconst dataset = await client.getDataset(\"<dataset_id>\");\n// Returns: { id: \"...\", name: \"...\", total_size: 1024, connectors: [...], ... }\n\n// Create a dataset\nconst dataset = await client.createDataset({\n  name: \"Tech Docs\",\n  chunk_method: \"naive\",\n});\n\n// Update a dataset\nawait client.updateDataset(\"<dataset_id>\", { name: \"New Name\" });\n\n// Delete datasets by IDs\nawait destructiveClient.deleteDatasets([\"<id1>\", \"<id2>\"]);\n```\n\n## Document\n\n```javascript\n// Upload documents\nawait client.uploadDocuments(\"<dataset_id>\", [\"./report.pdf\", \"./notes.txt\"]);\n\n// Override display names when paths are temporary/task IDs\nawait client.uploadDocuments(\"<dataset_id>\", [\n  { path: \"./tmp/task-output\", name: \"report.pdf\" },\n]);\n\n// List documents (supports page, page_size, id, name, orderby, desc, keywords, suffix, types, run, metadata, metadata_condition, return_empty_metadata)\nconst docs = await client.listDocuments(\"<dataset_id>\");\n\n// Get a single document by ID\nconst doc = await client.getDocument(\"<dataset_id>\", \"<doc_id>\");\n\n// Update a document\nawait client.updateDocument(\"<dataset_id>\", \"<doc_id>\", {\n  name: \"Renamed\",\n  parser_config: { pages: [[1, 2]] },\n  chunk_method: \"knowledge_graph\",\n  enabled: 1,\n  meta_fields: { author: \"Alice\" },\n});\n\n// Delete doc"},{"path":"references/COMMANDS.md","content":"# Command Reference\n\nDeletion commands, metadata removal or unscoped metadata updates, and ingestion with `--delete` require `--confirm-destructive` after the target operation is authorized. Missing or false confirmation fails before the destructive HTTP request. Ordinary reads and stopping parsing do not require it.\n\nPractical CLI reference for `scripts/ragflow.js`, organized around common RAGFlow workflows. It intentionally prioritizes daily operations over exhaustive REST API coverage.\n\nUse `--json` on any command to suppress status text and print only machine-readable JSON.\nJSON-valued options such as `--parser-config`, `--prompt-config`, and `--dsl` accept either inline JSON or `@path/to/file.json`.\n\nOn command failure with `--json`, the CLI exits non-zero and prints a structured error envelope:\n\n```json\n{\n  \"error\": {\n    \"message\": \"API Error: Unauthorized\",\n    \"raw_message\": \"Unauthorized\",\n    \"code\": 401,\n    \"status\": 401,\n    \"command\": \"list-models\"\n  }\n}\n```\n\n## Table of Contents\n\n- [Scenario Map](#scenario-map)\n- [Knowledge Base Setup](#knowledge-base-setup)\n- [Document Ingestion](#document-ingestion)\n- [Parsing and Chunking](#parsing-and-chunking)\n- [Information Retrieval](#information-retrieval)\n- [RAG Assistant Operation](#rag-assistant-operation)\n- [Agent Operation](#agent-operation)\n- [Embedded Website Access](#embedded-website-access)\n- [Discovery and Configuration](#discovery-and-configuration)\n- [System Operations](#system-operations)\n\n## Scenario Map\n\n| Scenario | Use it for |\n|---|---|\n| [Knowledge Base Setup](#knowledge-base-setup) | Create and maintain datasets before ingesting files |\n| [Document Ingestion](#document-ingestion) | Upload, inspect, update, and remove source documents |\n| [Parsing and Chunking](#parsing-and-chunking) | Turn documents into searchable chunks and manage chunk content |\n| [Information Retrieval](#information-retrieval) | Query datasets directly without creating a chat assistant |\n| [RAG Assistant Operation](#rag-assistant-operation) | Create chat assistants, manage sessions, and run Q&A |\n| [Agent Operation](#agent-operation) | Create tool-capable agents, manage sessions, and run agent chat |\n| [Embedded Website Access](#embedded-website-access) | Generate iframe/widget code and call shared chatbots/agentbots |\n| [Discovery and Configuration](#discovery-and-configuration) | Inspect available LLM models, and manage model providers/instances (v0.27.2) |\n| [System Operations](#system-operations) | Check health/version and inspect log-level settings |\n\n## Knowledge Base Setup\n\nUse this section when the user is creating or maintaining the dataset container that everything else depends on.\n\n```bash\nnode {baseDir}/scripts/ragflow.js create-dataset --name \"Tech Docs\" --chunk-method naive\nnode {baseDir}/scripts/ragflow.js create-dataset --name \"Tech Docs\" --embedding-model \"text-embedding-v4@Tongyi-Qianwen\"\nnode {baseDir}/scripts/ragflow.js list-datasets\nnode {baseDir}/scripts/ragflow.js get-dataset "}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Manage everyday RAGFlow datasets, retrieval, chat, and agents. Skill: RAGFlow Skill Owner: lunarcache Summary: Manage everyday RAGFlow datasets, retrieval, chat, and agents. Tags: latest:3.0.0 Version history: v3.0.0 | 2026-09-25T02:38:34.249Z | user Require explicit authorization flags for destructive requests; harden embedded HTML and widget messages; validate multipart upload names. RAGFlow v0.27.2 APIs only. v2.0.1 | 2026-09-25T02:14:38.739Z | user Remove compatibility analy","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1600,"uniquenessScore":46,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T17:08:31.525Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T23:50:36.874Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}