Skip to content
Research
Agent

TOOL_ARTIFACTS

*(optional, if `tool_artifacts.enabled && tool_artifacts.resolve_handles_in_args`, default on)* Resolves `art_xxxxxxxx` artifact handles found in tool-call arguments to their real references (`ThreadState.tool_artifacts[].real_ref`) before the tool executes (issue #4676). Runs

From plugin
deer-flow
85k2 skills2 agents

Claude Code

$ npx -y skills add bytedance/deer-flow --agent claude-code

Agent definition

TOOL_ARTIFACTS.md

Tool artifact middleware

Resolution

*(optional, if `tool_artifacts.enabled && tool_artifacts.resolve_handles_in_args`, default on)* Resolves `art_xxxxxxxx` artifact handles found in tool-call arguments to their real references (`ThreadState.tool_artifacts[].real_ref`) before the tool executes (issue #4676). Runs after the outer receipt layer and before authorization/guardrail, sandbox-audit, read-before-write and progress policies; the same resolved arguments reach policy and execution. Declarative constraints enforce this order even after extension insertion. It mutates only the request args, never the message history. Handles may appear bare, inside backticks, or nested in dict/list args; unknown or expired handles return an error ToolMessage naming the missing handles and up to ten current handles, without executing the tool. This applies even to an empty registry; ordinary concrete arguments and disabled-feature behavior remain unchanged. Both config flags must be on — disabling `tool_artifacts.enabled` stops resolution for threads that still carry registry state.

Task-note batch reservations read the same resolver's argument view from the call-local `ToolRuntime.state`, using `RESOLVED_TOOL_CALL_ARGS_KEY` from `deerflow.agents.task_continuity.state`. Aliases share a slot by resolved key; message history and checkpoints remain unchanged.

Capture

*(optional, if `tool_artifacts.enabled`, default on)* Captures lightweight artifact references from tool results into `ThreadState.tool_artifacts` (a reducer channel, so entries survive summarization compaction). `tool_artifacts.enabled` gates the whole middleware (capture and consumption tracking); when off, `before_model` returns nothing regardless of registry state. Runs as a `before_model` hook (never wraps a `ToolMessage` in a `Command`). `ThreadState.tool_artifact_processed` stores deduplicated hashes of processed result and settled consuming-call occurrences through an additive reducer. It records empty results too. The ledger is independent of registry retention and survives checkpoint reload, graph recreation and compaction; it is not trimmed with artifacts and grows by a small identity record per processed occurrence. Never replace it with a process-local memo or infer it from currently retained handles. A missing handle gets one retry before its consuming-call occurrence settles, so permanently unknown or evicted handles are scanned at most twice, including across restarts; same-round consumption resolves against state plus pending captures. Capture and consumption updates concatenate list channels so neither is lost. Position-independent in the tool-execution wrap chain: it is a `before_model` hook reading state messages, so it sees the normalized results stored in state regardless of its wrap position (error results are skipped at extraction via `status == "error"`); it is appended after ToolErrorHandlingMiddleware for readability only. Handles are `art_` + 8 hex chars derived deterministically from (thread_id, durable ToolMessage.id, provider tool_call_id, per-result ordinal). Provider call IDs may repeat across turns; graph-assigned message IDs distinguish occurrences and remain stable after compaction. Standalone ID-less hook callers must supply distinct call indices. These short hashes are identifiers, not ownership credentials. Extraction combines all of: structured-content string values under known keys (`file`/`path`/`url`/`task_id`/...) as concrete refs (unknown or non-reference payloads fall back to complete JSON `data` only when they fit 4096 UTF-8 bytes, 1024 nodes and 32 levels; empty and oversized payloads are skipped before unbounded serialization), `file`/`image` content blocks with HTTP(S), Unix-absolute or drive-absolute references (`data:`/`blob:` URIs are rejected so embedded-resource payloads never enter state or tool args), and conservative free-text scanning of both text blocks and plain-string results such as built-in sandbox tool output (sandbox paths + remote file URLs including query/fragment suffixes, gated by `detect_refs_in_text`). The reducer enforces only an absolute ceiling (1000); the configured `tool_artifacts.max_entries` is a per-agent sliding retention window: when a capture round would exceed it, the middleware appends a trailing `{"op": "trim_to", "keep": N}` directive and the reducer evicts the oldest entries (fresh captures are always registered — nothing freezes at the cap), so agents with different configs in one process do not share a cap. Reference entries contain metadata (path/URL, name, type, MIME). The JSON compatibility fallback is an explicitly bounded exception. Concrete path/URL keys reject prose and relative paths; remote task IDs use a separate non-empty, whitespace-free, 256-character token gate. File references on all extraction paths are bounded to 4096 UTF-8 bytes. Structured traversal is bounded before fallback encoding, and valid content-block references are still captured if structured data is rejected.

Free-text remote file detection checks the complete URL path for a supported file suffix. Query strings and fragments are retained in the reference and do not determine its file type; a file-like prefix inside a longer path is not registered as a shortened URL. Supported file suffixes are matched without case sensitivity. Both URL and sandbox-path text scans strip common trailing ASCII/CJK prose punctuation and closing quotes or brackets. CJK closers paired with openers inside the detected reference are preserved, so a numbered glob result such as `/mnt/user-data/workspace/项目(归档)` retains its complete name through capture, checkpoint persistence and subsequent handle resolution.

Durable projection

Artifact handles are projected with working notes and summary history in the hidden HumanMessage data block when `tool_artifacts.enabled` and `inject_model_context` are enabled. Every model-visible artifact label (display name, type, tool name, MIME type) is

Read more
@bytedance
Ships withdeer-flow

On February 28th, 2026, DeerFlow claimed the 🏆 #1 spot on GitHub Trending following the launch of version 2. Thanks a million to our incredible community — you made this happen!

85k29 skills2 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
85.2k
Star history of bytedance/deer-flow on GitHub, a chart by star-history.com

Other agents on deer-flow.

TOOL_OUTPUT_PERSISTENCE

TOOL_OUTPUT_PERSISTENC…

Agent

Host and sandbox outputs share a filename helper whose fixed-length SHA-256 suffix hashes the raw call ID and UTF-8 content with…

@bytedance@bytedanceInstall Agent

More agents from other plugins.

cnki-researcher

cnki-researcher

Agent

CNKI Research Assistant - helps with literature search, journal lookup, and indexing queries on CNKI (中国知网). Use proactively when…

@cookjohn@cookjohnInstall Agent

Questions about TOOL_ARTIFACTS.

Which coding agents can use TOOL_ARTIFACTS?
TOOL_ARTIFACTS installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.