外观
SDK 与 stream-json 协议
dcl 可以作为 Agent SDK 的后端运行:宿主程序以子进程启动 dcl,在 stdin/stdout 上逐行交换 JSON(NDJSON),一个进程内可以连续进行多轮对话,并在对话过程中处理工具审批、Hook 回调和宿主提供的 MCP 工具。协议与参考 CLI 的 stream-json 控制协议一致,为该协议编写的 SDK 可以直接驱动 dcl。
Java 项目可以使用 agent-cli-sdk,见下文 Java SDK。
启动
bash
dcl --input-format stream-json --output-format stream-json \
--permission-mode default --permission-prompt-tool stdio--input-format stream-json要求--output-format stream-json。--include-partial-messages:额外输出stream_event增量事件。--replay-user-messages:回显收到的每条用户消息(带uuid)。--permission-prompt-tool stdio:工具审批交给宿主(SDK 模式下默认如此,参数用于兼容)。- 其它参数(
--model、--system-prompt、--allowedTools、--max-turns、--json-schema、--resume等)与非交互模式相同。
stdin 关闭后,dcl 处理完已排队的消息再退出。
宿主发送的消息
用户消息:
json
{"type":"user","message":{"role":"user","content":"列出 src 下的文件"},"parent_tool_use_id":null,"uuid":"6f0c…"}content 可以是字符串,也可以是内容块数组(text、image)。uuid 可选;没有时 dcl 自动生成。session_id 省略、为空或为 "default" 时都视为当前会话。
控制请求:
json
{"type":"control_request","request_id":"req_1","request":{"subtype":"initialize"}}dcl 用 control_response 回答:
json
{"type":"control_response","response":{"subtype":"success","request_id":"req_1","response":{…}}}失败时 subtype 为 error,error 字段给出原因。
dcl 输出的消息
system(subtype: init):每个进程一次,含session_id、cwd、model、tools(含 MCP 与宿主 MCP 工具)、mcp_servers、permissionMode、slash_commands、agents。assistant:每个内容块一条,message.content为text、thinking或tool_use;同一轮模型请求的块共享message.id。user:工具结果,content为tool_result块;MCP 工具的结果保留为内容块数组。stream_event:仅在--include-partial-messages时输出,event为message_start、content_block_start、content_block_delta(text_delta、thinking_delta、input_json_delta)、content_block_stop、message_delta、message_stop。result:每轮一条,含subtype(success、error_max_turns、error_during_execution)、is_error、result、num_turns、duration_ms、total_cost_usd(会话累计)、usage、structured_output,以及permission_denials(本轮被规则、模式、Hook 或宿主拒绝的工具调用)。prompt_suggestion:initialize打开promptSuggestions后,每轮成功结束时给出下一句建议。
所有消息都带 session_id 和 uuid。为兼容旧的脚本,text、tool_start、tool_result、usage 等事件行仍然保留,SDK 可以忽略不认识的类型。
宿主可以发送的控制请求
会话初始化:
initialize:注册hooks(回调 ID)、sdkMcpServers(宿主 MCP 服务器名)、agents(子 agent 定义)、agent(主线程使用的 agent)、systemPrompt/appendSystemPrompt、jsonSchema、promptSuggestions、agentProgressSummaries。只能发送一次,返回命令、agent、模型和输出风格列表。
回合控制:
interrupt:中断当前回合,该回合的result为error_during_execution。cancel_async_message(message_uuid):取消尚未开始的排队消息,返回cancelled。
会话设置:
set_permission_mode(mode):default、acceptEdits、plan、bypassPermissions、dontAsk。set_model(model):后续回合使用的模型。set_max_thinking_tokens(max_thinking_tokens):映射为思考强度——0关闭,≤4096 为 low,≤16384 为 medium,≤32768 为 high,更大为 max,null恢复默认。apply_flag_settings(settings):支持model、effortLevel、permissions.defaultMode,其它键报错。get_settings:返回合并后的effective、按优先级排列的sources(user → project → local → flag)和实际生效的applied.model、applied.effort。
状态查询:
mcp_status:所有 MCP 服务器及状态(connected、pending、failed、disabled)。get_context_usage:上一次请求的上下文占用,按系统提示、工具定义、消息、输出 Schema 分类,含totalTokens、maxTokens、percentage。
资源操作:
mcp_toggle(serverName、enabled)、mcp_reconnect(serverName):启停或重启已配置的 MCP 服务器。reload_plugins:重新加载插件,返回命令、agent、插件和 MCP 状态。stop_task(task_id):停止后台 shell 或后台任务。rewind_files(user_message_id、dry_run):把文件恢复到这条用户消息之前,user_message_id用发送时的uuid。返回canRewind、filesChanged、insertions、deletions;之后有人改过同一文件时拒绝。检查点只在 Git 工作区中记录,见回退。seed_read_state:接受并校验参数;dcl的编辑工具不依赖读取缓存,因此无需额外处理。
回合进行中可以发送 interrupt、cancel_async_message、set_permission_mode 和所有查询类请求;set_model 等其它修改需要等回合结束。mcp_set_servers 不支持:MCP 服务器请用 dcl mcp add 配置,或通过 initialize.sdkMcpServers 由宿主提供。
dcl 发给宿主的控制请求
can_use_tool:工具审批,含tool_name、input、tool_use_id。宿主回答{"behavior":"allow","updatedInput":{…}}或{"behavior":"deny","message":"…"},可附带updatedPermissions(规则写入会话或设置文件)。hook_callback:执行宿主注册的 Hook,含callback_id、input、tool_use_id,回答 Hook 输出对象。mcp_message:转发给宿主 MCP 服务器的 JSON-RPC 消息,回答{"mcp_response":{…}}。elicitation:MCP 服务器请求用户输入,回答{"action":"accept","content":{…}}、decline或cancel。
审批或回调不再需要时(例如回合被中断),dcl 发送 control_cancel_request,宿主可以丢弃对应请求。
完整示例
bash
printf '%s\n' \
'{"type":"control_request","request_id":"i1","request":{"subtype":"initialize"}}' \
'{"type":"user","message":{"role":"user","content":"what time is it"}}' \
| dcl --input-format stream-json --output-format stream-json --permission-mode plan下面是一次实际运行的输出(使用本地测试模型,省略了部分字段,旧格式事件行未列出)。模型请求了一个当前会话中没有的工具,计划模式拒绝了这次调用,拒绝记录出现在 result.permission_denials 中:
json
{"response": {"request_id": "i1", "response": {"commands": "…", "agents": "…", "models": "…"}, "subtype": "success"}, "type": "control_response"}
{"type": "system", "subtype": "init", "session_id": "4472dafa-acf8-4c0a-a281-2f9f0f03398c", "model": "mock-model", "permissionMode": "plan", "tools": ["Skill", "NotebookEdit", "LSP", "…"]}
{"type": "assistant", "message": {"content": [{"id": "time-1", "input": {}, "name": "mcp__app__server_time", "type": "tool_use"}], "id": "msg_f84582da70bb4d758add0ba12f9e1797", "role": "assistant"}, "session_id": "4472dafa-acf8-4c0a-a281-2f9f0f03398c"}
{"type": "user", "message": {"content": [{"content": "Permission denied: Plan mode: write operations are not allowed", "is_error": true, "tool_use_id": "time-1", "type": "tool_result"}], "role": "user"}, "session_id": "4472dafa-acf8-4c0a-a281-2f9f0f03398c"}
{"type": "assistant", "message": {"content": [{"text": "Tool said: Permission denied: Plan mode: write operations are not allowed", "type": "text"}], "id": "msg_73f758984d53411796b0c999fbcc9adf", "role": "assistant"}, "session_id": "4472dafa-acf8-4c0a-a281-2f9f0f03398c"}
{"type": "result", "subtype": "success", "is_error": false, "result": "Tool said: Permission denied: Plan mode: write operations are not allowed", "num_turns": 2, "duration_ms": 108, "total_cost_usd": 0.0, "permission_denials": [{"tool_input": {}, "tool_name": "mcp__app__server_time", "tool_use_id": "time-1"}], "session_id": "4472dafa-acf8-4c0a-a281-2f9f0f03398c"}Java SDK
agent-cli-sdk 是这套协议的 Java 实现(Java 8+,无第三方依赖),把 CLI 路径指向 dcl 即可:
java
import nexus.io.agent.sdk.Agent;
import nexus.io.agent.sdk.AgentOptions;
import nexus.io.agent.sdk.PermissionMode;
import nexus.io.agent.sdk.message.ResultMessage;
import nexus.io.agent.sdk.permission.PermissionResult;
public class DclExample {
public static void main(String[] args) {
AgentOptions options = new AgentOptions()
.cliPath("dcl")
.model("deepseek-flash")
.permissionMode(PermissionMode.DEFAULT)
.canUseTool((tool, input, context) -> "Bash".equals(tool)
? PermissionResult.deny("Bash is disabled")
: PermissionResult.allow());
ResultMessage result = Agent.query("总结 README.md", options, null);
System.out.println(result.getResult());
}
}dcl 特有的参数用 extraArg 传入,例如 .extraArg("api-format", "anthropic")、.extraArg("data-dir", "/path/to/data")。SDK 仓库的 examples/tio-boot-agent-demo 是一个完整的 HTTP 服务示例:一次性查询、SSE 流式输出、多轮会话、JVM 内 MCP 工具和服务端工具策略。
Java SDK
Java 程序可以直接使用 Java SDK,不需要自己实现这个协议。