mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-11-12 22:20:33 +00:00
* docs: turn README into an index and move reference detail to docs/guide The README had grown to 393 KB because every change appended its notes there. The text moves verbatim into 18 topic guides under docs/guide/; only headings are re-leveled and relative links re-pointed. The README keeps the introduction, a quick start and a guide index. Contributor test notes move to CONTRIBUTING.md. * docs: send user docs to topic guides and budget the root README The rule 'update README.md for user-facing changes' is what grew the README. Guidance now points to docs/guide/, and check_agent_guidance.py fails when the root README exceeds 16 KiB (AG003). * chore: remove unreferenced screenshots and finished plan notes pr-build/ holds two PR screenshots (3 MB) from #1986. plans/ holds the plan for the merged #4049. docs/SKILL_NAME_CONFLICT_FIX.md is a February change note. Nothing references them. * docs: route always-loaded AGENTS.md files to scoped guides * docs(agents): cut scoped guides to scope, verify, traps, decisions Each AGENTS.md keeps four kinds of content: the scope of the directory, the verification commands, traps a local test run does not show, and decisions the code cannot state. Values, field lists, function inventories, test names, issue numbers and history are deleted, because the code, the tests and git state them. Search and fetch providers share one community guide. Four guides with no remaining content are removed. The size check now allows 6 KiB per file (hard limit 8 KiB) and 24 KiB per chain (hard limit 32 KiB). * style: format frontend guide table and guidance test imports --------- Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
140 lines
8.3 KiB
Markdown
140 lines
8.3 KiB
Markdown
# API Access and Python Client
|
||
|
||
## Existing-Run Stream Actions
|
||
|
||
Existing-run SSE joins are observation-only on `GET`: supplying
|
||
`action=interrupt|rollback` returns `405`. Cancellation on this stream route is
|
||
`POST`-only and requires the `runs:cancel` permission. Accordingly, the OpenAPI
|
||
contract exposes `action` and `wait` only on `POST`; the `GET` operation exposes
|
||
only its path parameters.
|
||
|
||
## Personal Access Tokens
|
||
|
||
Non-interactive clients (CI pipelines, scripts, server-to-server integrations)
|
||
can call the Gateway API with a **personal access token (PAT)** instead of a
|
||
browser session. Create one while logged in via `POST /api/v1/auth/pats` — the
|
||
raw `dfp_...` value is shown exactly once; only its SHA-256 digest is stored —
|
||
then send it as a Bearer credential:
|
||
|
||
```http
|
||
POST /api/threads/search
|
||
Authorization: Bearer dfp_...
|
||
Content-Type: application/json
|
||
|
||
{}
|
||
```
|
||
|
||
Each token runs with its owning user's identity (owner filtering and per-user
|
||
memory keep working), carries a scope set that can only narrow that user's
|
||
permissions, and is admitted only to the thread/run lifecycle routes — every
|
||
other route answers `403` to PAT callers, and a PAT never carries admin
|
||
capability. Tokens can be listed and revoked at any time; revocation is
|
||
immediate. PATs require a database backend (SQLite/PostgreSQL). Full
|
||
reference: [API Reference — Personal Access Tokens](../../backend/docs/API.md#personal-access-tokens).
|
||
|
||
## Embedded Python Client
|
||
|
||
User messages are framed as untrusted input. Reserved XML-like tags are escaped
|
||
for model context only when present; tag-free URLs and shell commands retain
|
||
their ampersands unchanged. Encoded payloads include a note to decode exactly
|
||
once when reproducing the original text in files, code, or tool-call arguments. This preserves XML
|
||
angle brackets and literal HTML entities in verbatim-content requests while
|
||
keeping user-supplied tags separate from framework instructions. Copied encoding
|
||
notes are treated as user text; only request-local program state permits reuse
|
||
of an already encoded frame.
|
||
|
||
`chat()` and `stream()` preserve text appended by model middleware before the
|
||
first state snapshot, emitting only the suffix after the streamed text.
|
||
|
||
For `DeerFlowClient(agent_name="researcher")`, the named agent's `mcp_plugins`
|
||
selection applies to both the lead agent and its `task` / `batch_task`
|
||
delegations: `null` inherits all enabled MCP plugins, `[]` selects none, and
|
||
installation IDs select only those plugins. Call `client.reset_agent()` after
|
||
editing the saved agent configuration to refresh the selection.
|
||
|
||
`DeerFlowClient.stream()` includes `summary_text` in each `values` event. This is the current compacted context summary, or `None` when absent. Consumers can record changes without reading checkpoint internals; repeated snapshots may carry the same summary, and an initial snapshot may already contain one from an earlier turn.
|
||
|
||
DeerFlow can be used as an embedded Python library without running the full HTTP services. The `DeerFlowClient` provides direct in-process access to all agent and Gateway capabilities, returning the same response schemas as the HTTP Gateway API.
|
||
|
||
The HTTP Gateway exposes `DELETE /api/threads/{thread_id}` to remove a thread's
|
||
files, checkpoints, and metadata. If checkpoint deletion fails, the Gateway
|
||
returns 500 and retains the owner record for retry.
|
||
[Thread cleanup API](../../backend/docs/API.md#thread-cleanup)
|
||
|
||
An embedded `DeerFlowClient(config_path="custom/config.yaml")` keeps the process
|
||
config singleton on that file, even after a working-directory change. Later edits
|
||
to the file are still detected. Call `reload_app_config()` without a path to resume
|
||
ambient config discovery, or `reset_app_config()` to clear the cached selection.
|
||
|
||
For database-backed run events, deleting a run preserves its thread's sequence watermark. Thread deletion removes that watermark once no events remain, allowing a recreated thread to restart at sequence 1. Owner-scoped deletion preserves the watermark when another owner's events remain.
|
||
|
||
Single-process JSONL event storage also retains the thread sequence watermark
|
||
across run deletion and restarts, so clients using `after_seq` do not miss later
|
||
messages. Keep `runs/.seq-watermark` with the run files when backing up this
|
||
backend. New or replaced watermarks inherit the deleted run file's permission bits.
|
||
Deleting the complete thread removes the watermark and resets allocation.
|
||
|
||
Thread IDs may be supplied by callers and do not have to be UUIDs. Explicit
|
||
IDs must contain 1–64 ASCII letters, digits, hyphens, or underscores
|
||
(`^[A-Za-z0-9_-]{1,64}$`). DeerFlow generates a UUID only when `thread_id` is
|
||
omitted or `None`; an explicitly supplied empty string is invalid.
|
||
Concurrent `POST /api/threads` requests and automatic run metadata creation share
|
||
same-ID admission in one Gateway, preserving the first thread's metadata and status.
|
||
HTTP retries also preserve its current checkpoint. SQL-backed Gateways retain
|
||
duplicate-insert recovery across workers.
|
||
Existing route-addressable threads created under older, looser rules remain
|
||
readable and deletable, but cannot start new runs or create new filesystem or
|
||
sandbox state. Legacy deletion skips local path cleanup when the ID is not
|
||
safe under the canonical contract. For canonical legacy threads whose
|
||
conversation exists only in LangGraph checkpoints, DeerFlow seeds an empty
|
||
run-event feed from the checkpoint before the first new run so
|
||
`/messages/page` keeps both the old and new turns.
|
||
|
||
```python
|
||
from deerflow.client import DeerFlowClient
|
||
|
||
client = DeerFlowClient()
|
||
|
||
# Chat
|
||
response = client.chat("Analyze this paper for me", thread_id="my-thread")
|
||
|
||
# Streaming (LangGraph SSE protocol: values, messages-tuple, end)
|
||
for event in client.stream("hello"):
|
||
if event.type == "messages-tuple" and event.data.get("type") == "ai":
|
||
print(event.data["content"])
|
||
elif event.type == "messages-tuple" and event.data.get("type") == "tool" and "artifact" in event.data:
|
||
# Structured tool artifacts (for example, ask_clarification cards)
|
||
# are preserved when the ToolMessage provides one.
|
||
print(event.data["artifact"])
|
||
|
||
# Configuration & management — returns Gateway-aligned dicts
|
||
models = client.list_models() # {"models": [...]}
|
||
skills = client.list_skills() # {"skills": [...]}
|
||
client.update_skill("web-search", enabled=True)
|
||
client.upload_files("thread-1", ["./report.pdf"]) # {"success": True, "files": [...]}
|
||
client.set_goal("thread-1", "finish the implementation and make all tests pass")
|
||
client.get_goal("thread-1") # {"goal": {...}} or {"goal": None}
|
||
client.clear_goal("thread-1")
|
||
```
|
||
|
||
When continuing a thread, `values` still contains the full conversation state, while `messages-tuple` and `end.usage` cover only the current turn.
|
||
|
||
The embedded client's `end.usage` sums usage deltas across streamed chunks,
|
||
including providers such as native Gemini that report usage more than once per
|
||
reply. The completed message's usage is reconciled without counting those
|
||
chunks again; a lower completed-message count does not subtract tokens already
|
||
reported by chunks. Signed provider corrections in chunks remain supported, as
|
||
do providers that report usage only at completion.
|
||
|
||
Concurrent `upload_files()` calls preserve filenames absent at the start of each
|
||
call by assigning numeric suffixes and returning the actual saved names. The same
|
||
rule applies to new Markdown companions. Exact names already present retain
|
||
replacement behavior. Convertible files use one private source capture through
|
||
all filename retries and conversion, preserving the original permissions and
|
||
timestamps. Detected staging-file substitution is rejected; staging cleanup
|
||
failures are logged without masking the upload outcome.
|
||
|
||
The HTTP Gateway accepts `values`, `messages-tuple`, `updates`, `debug`, `tasks`, `checkpoints`, and `custom` stream modes. Unsupported modes such as `messages` and `events`, unsupported non-default run options such as webhooks, delayed execution, or `multitask_strategy="enqueue"`, and undeclared SDK options such as checkpoint durability overrides return `422` before execution instead of being silently ignored or downgraded.
|
||
|
||
All dict-returning methods are validated against Gateway Pydantic response models in CI (`TestGatewayConformance`), ensuring the embedded client stays in sync with the HTTP API schemas. See `backend/packages/harness/deerflow/client.py` for full API documentation.
|