refactor(agent-runner): remove protocol_version from various components and update related documentation

This commit is contained in:
huanghuoguoguo
2026-06-09 20:57:06 +08:00
parent f92029e245
commit 35661081ad
18 changed files with 36 additions and 122 deletions

View File

@@ -72,7 +72,7 @@ LangBot 不提供 host-side inline history window。简单 runner 如果需要
### 4.1 History
```python
await api.history.page(conversation_id=ctx.context.conversation_id,
await api.history_page(conversation_id=ctx.context.conversation_id,
before_cursor=ctx.context.latest_cursor,
limit=50, direction="backward", include_artifacts=False)
```
@@ -92,7 +92,7 @@ class HistoryPage(BaseModel):
### 4.2 Search
```python
await api.history.search(query="用户之前提到的数据库连接信息",
await api.history_search(query="用户之前提到的数据库连接信息",
filters={"conversation_id": ..., "event_types": ["message.received"]},
top_k=10)
```
@@ -154,4 +154,4 @@ Agent 自管 context 不代表无限制访问。LangBot 仍必须控制:每次
官方 runner 插件可以把状态寄宿在 LangBot但必须和第三方 runner 一样通过公开 Host API 消费。LangBot core 不内置官方 agent 的业务流程prompt 组装、tool loop、RAG 编排、summary/compaction、"local-agent 专用"状态字段)。
官方 local-agent 应作为"依附 LangBot 基础设施的复杂 runner 参考实现"transcript/history 通过 `api.history` 读取summary/checkpoint/外部 session id/用户偏好通过 `api.state` `api.storage` 保存,图片/文件/工具大结果通过 `api.artifacts` 读取,模型/工具/知识库通过 `api.models` / `api.tools` / `api.knowledge` 调用。这样 LangBot 保持为通用 agent host不变成内置 agent 框架。具体迁移要求见 [OFFICIAL_RUNNER_PLUGINS.md](./OFFICIAL_RUNNER_PLUGINS.md)。
官方 local-agent 应作为"依附 LangBot 基础设施的复杂 runner 参考实现"transcript/history 通过 `api.history_page()` / `api.history_search()` 读取summary/checkpoint/外部 session id/用户偏好通过 `api.state_get()` / `api.state_set()`storage 方法保存,图片/文件/工具大结果通过 `api.artifact_metadata()` / `api.artifact_read_range()` 读取,模型/工具/知识库通过 `api.invoke_llm()` / `api.call_tool()` / `api.retrieve_knowledge()` 调用。这样 LangBot 保持为通用 agent host不变成内置 agent 框架。具体迁移要求见 [OFFICIAL_RUNNER_PLUGINS.md](./OFFICIAL_RUNNER_PLUGINS.md)。

View File

@@ -137,14 +137,13 @@ class AgentRunnerDescriptor(BaseModel):
source: Literal["plugin"]
label: I18nObject
description: I18nObject | None = None
protocol_version: str = "1"
capabilities: AgentRunnerCapabilities # 见 PROTOCOL_V1 §4.3
permissions: AgentRunnerPermissions # 见 PROTOCOL_V1 §4.4
config_schema: list[DynamicFormItemSchema]
plugin: PluginRef | None = None
```
职责:调用 `plugin_connector.list_agent_runners()` 拉取 runner、校验 manifest`kind == AgentRunner``metadata.name/label` 存在、`protocol_version` 兼容、`spec.*` 类型正确)、输出 descriptor、缓存 discovery 结果并提供 `refresh()`。单个插件 manifest 失败只记 warning不影响其它 runner。`plugin:author/name/runner` 是稳定 id 格式;插件实例边界见 PROTOCOL_V1 §13。
职责:调用 `plugin_connector.list_agent_runners()` 拉取 runner、校验 manifest`kind == AgentRunner``metadata.name/label` 存在、`spec.*` 类型正确)、输出 descriptor、缓存 discovery 结果并提供 `refresh()`。单个插件 manifest 失败只记 warning不影响其它 runner。`plugin:author/name/runner` 是稳定 id 格式;插件实例边界见 PROTOCOL_V1 §13。
Host 内置 runner / adapter 不能作为 `AgentRunnerDescriptor.source` 绕过插件
runtime、`run_id``ctx.resources``AgentRunAPIProxy` 权限链。若需要
@@ -225,16 +224,7 @@ LangBot 可提供 host-owned state 让 runner 寄宿状态conversation / acto
三类数据与 working context 的边界、读取约束见 [AGENT_CONTEXT_PROTOCOL.md](./AGENT_CONTEXT_PROTOCOL.md)。AgentRunner 可读取这些能力,但不被迫使用 LangBot 作为唯一记忆系统。
### 4.8 Prompt / Instruction Package占位
当前 Query 入口不把 preprocessing 后的有效 prompt 放进 adapter metadata。目标形态是 Host 保存或生成一个 run-scoped instruction packagerunner 通过 Host API 拉取:
- Host 记录静态绑定 prompt、host hook / user plugin 产生的 instruction fragment、来源和审计信息。
- `ctx.context.available_apis` 增加 `prompt_get` 能力位表示拉取是否可用。
- Runner 拉取后仍由自己决定如何与 history、RAG、tool 结果、memory 和当前输入组装最终 prompt。
- Host 不实现通用 agentic prompt assembler也不把 Query entry adapter prompt 作为长期业务输入契约。
### 4.9 External harness resource projection
### 4.8 External harness resource projection
Claude Code、Codex、Kimi Code 等外部 harness runner 可能不直接调用 LangBot 的 model/tool loop而是把 LangBot 事件和授权资源句柄投影到自己的 harness 执行。Host 侧仍保持统一边界Host 负责构造 event-first context、资源授权、state/storage、EventLog/Transcript/ArtifactStore 和审计Host 或 binding policy 决定哪些 MCP bridge、skill-backed tool、artifact、history/state 句柄可投影给 runnerrunner plugin 把 scoped projection 转成目标 harness 可消费形式;所有 LangBot 资源访问必须经 SDK runtime / `AgentRunAPIProxy` / SDK-owned MCP bridge 转发并接受 Host 校验;外部 harness 负责自己的 native session、tool loop、压缩、权限模式和 resume但不能用 native tools 绕过 Host 授权。

View File

@@ -57,7 +57,6 @@ metadata:
en_US: Run a Dify application as a LangBot AgentRunner.
zh_Hans: 将 Dify 应用作为 LangBot AgentRunner 运行。
spec:
protocol_version: "1"
config: []
capabilities: # 字段语义见 PROTOCOL_V1 §4.3
streaming: true

View File

@@ -41,12 +41,12 @@ Agent / binding 的持久化形态。
外部 harness runnerClaude Code、Codex、Kimi Code 等)也是 `AgentRunner`:它们消费 event-first `AgentRunContext`、返回 `AgentRunResult`,并通过 Host 授权的 state/storage/artifact API 保存跨轮次指针。它们内部可以继续使用自己的 session、tool loop、MCP、上下文压缩和权限模型。
## 3. 版本协商
## 3. 协议演进
- `AgentRunnerManifest.protocol_version` 声明 runner 实现的协议大版本,当前为 `"1"`
- `AgentRuntimeContext.protocol_version``ctx.runtime.protocol_version`)声明 Host 下发的协议大版本。
- Host 发现 runner 时校验 `protocol_version` 兼容性;不兼容的 runner 不进入可用列表,只记 warning
- 字段级演进规则:新增可选字段不提升大版本;删除或改语义需要提升大版本
当前 AgentRunner 合同不暴露显式 `protocol_version` 字段。协议演进先按字段级兼容规则处理:
- 新增可选字段保持向后兼容
- 删除字段或改变既有字段语义需要在 SDK 发布前完成;发布后应走新的显式兼容方案
- 结果流演进Host **必须忽略未知 result type 并记录 warning**(除非该 type 明确要求强校验)。新增 result type 不提升大版本。
## 4. Discovery 协议
@@ -68,7 +68,6 @@ class AgentRunnerManifest(BaseModel):
name: str
label: I18nObject
description: I18nObject | None = None
protocol_version: str = "1"
capabilities: AgentRunnerCapabilities
permissions: AgentRunnerPermissions
context: AgentRunnerContextPolicy
@@ -324,7 +323,6 @@ class ContextAPICapabilities(BaseModel):
```python
class AgentRuntimeContext(BaseModel):
host: str = "langbot"
protocol_version: str = "1"
langbot_version: str | None = None
trace_id: str
deadline_at: float | None = None
@@ -548,38 +546,36 @@ Host 必须校验 `state.updated` 的 scope、key、value 大小和 JSON 可序
```python
# Model
await api.models.invoke(model_id, messages, tools=None, extra_args=None)
await api.models.stream(model_id, messages, tools=None, extra_args=None)
await api.models.rerank(model_id, query, documents, top_k=None)
await api.invoke_llm(model_id, messages, funcs=None, extra_args=None)
async for chunk in api.invoke_llm_stream(model_id, messages, funcs=None, extra_args=None):
...
await api.invoke_rerank(rerank_model_id, query, documents, top_k=None)
# Tool
await api.tools.get_detail(tool_name)
await api.tools.call(tool_name, parameters)
await api.get_tool_detail(tool_name)
await api.call_tool(tool_name, parameters)
# Knowledge
await api.knowledge.retrieve(kb_id, query_text, top_k=5, filters=None)
await api.retrieve_knowledge(kb_id, query_text, top_k=5, filters=None)
# History返回 Transcript projection不返回原始平台 payload
await api.history.page(conversation_id=None, before_cursor=None, after_cursor=None,
await api.history_page(conversation_id=None, before_cursor=None, after_cursor=None,
limit=50, direction="backward", include_artifacts=False)
await api.history.search(query, filters=None, top_k=10)
await api.history_search(query, filters=None, top_k=10)
# Event返回稳定 event envelope 或受限 raw ref不默认返回大 payload
await api.events.get(event_id)
await api.events.page(before_cursor=None, limit=50)
await api.event_get(event_id)
await api.event_page(before_cursor=None, limit=50)
# Artifact必须支持大小限制、MIME 校验、过期时间和授权范围)
await api.artifacts.metadata(artifact_id)
await api.artifacts.read_range(artifact_id, offset=0, length=65536)
await api.artifacts.open_stream(artifact_id)
await api.artifact_metadata(artifact_id)
await api.artifact_read_range(artifact_id, offset=0, length=65536)
# State / Storage
await api.state.get(scope, key); await api.state.set(scope, key, value); await api.state.delete(scope, key)
await api.storage.get(area, key); await api.storage.set(area, key, value)
await api.storage.delete(area, key); await api.storage.list(area, prefix=None)
# Platform受限能力默认不开放需 manifest + binding policy + 用户审批同时允许)
await api.platform.request_action(action, target, payload)
await api.state_get(scope, key); await api.state_set(scope, key, value); await api.state_delete(scope, key)
await api.state_list(scope, prefix=None)
await api.get_plugin_storage(key); await api.set_plugin_storage(key, value); await api.delete_plugin_storage(key)
await api.get_workspace_storage(key); await api.set_workspace_storage(key, value); await api.delete_workspace_storage(key)
```
`state``storage` 的建议边界:`state` 放小型 JSONconversation / actor / runner / binding`storage` 放 blob 或较大数据插件私有数据、workspace 数据、checkpoint