@metagptx/deepflow-suite-cli 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -2
- package/bin/deepflow-suite.js +77 -0
- package/bundle/deepflow-release.json +185 -0
- package/bundle/skills/deepflow-suite/SKILL.md +79 -0
- package/bundle/skills/deepflow-suite/manifest.yaml +20 -0
- package/bundle/skills/df-agentctrl/SKILL.md +143 -0
- package/bundle/skills/df-agentctrl/assets/agent.json +8 -0
- package/bundle/skills/df-agentctrl/references/maintenance.md +68 -0
- package/bundle/skills/df-agentctrl/scripts/to_snapshot.py +26 -0
- package/bundle/skills/df-agentrt/SKILL.md +191 -0
- package/bundle/skills/df-agentrt-repo/SKILL.md +83 -0
- package/bundle/skills/df-task/SKILL.md +177 -0
- package/bundle/skills/df-task/assets/payload-examples/adjudication.json +5 -0
- package/bundle/skills/df-task/assets/payload-examples/artifact_published.json +6 -0
- package/bundle/skills/df-task/assets/payload-examples/help_requested.json +5 -0
- package/bundle/skills/df-task/assets/payload-examples/run_outcome.json +5 -0
- package/bundle/skills/df-task/assets/payload-examples/run_terminated.json +4 -0
- package/bundle/skills/df-task/assets/payload-examples/summary.json +4 -0
- package/bundle/skills/df-task/references/fact-types.md +48 -0
- package/bundle/skills/df-task/skill_test.go +201 -0
- package/bundle/skills/df-taskdriver/SKILL.md +126 -0
- package/bundle/skills/df-workbench/SKILL.md +64 -0
- package/bundle/skills/df-workbench/manifest.yaml +5 -0
- package/manifest.json +68 -0
- package/package.json +28 -4
- package/scripts/build-package.mjs +12 -0
- package/skills/deepflow-suite/SKILL.md +79 -0
- package/skills/deepflow-suite/manifest.yaml +20 -0
- package/src/bundle-installer.mjs +189 -0
- package/src/bundle.mjs +128 -0
- package/src/cli-install.mjs +140 -0
- package/src/commands/doctor.mjs +35 -0
- package/src/commands/install.mjs +32 -0
- package/src/constants.mjs +30 -0
- package/src/linker.mjs +96 -0
- package/src/manifest.mjs +72 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: df-agentrt
|
|
3
|
+
description: 在 DeepFlow Agent Runtime 里执行任务时使用。说明你所处的运行环境、产出物怎么交付、工作目录的生命周期,以及 df-agentrt 的命令。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DeepFlow Agent Runtime
|
|
7
|
+
|
|
8
|
+
你运行在 **DeepFlow Agent Runtime** 上。这是一个把「会话 + 多轮消息 + 代码仓库」
|
|
9
|
+
管起来的服务,你现在执行的是其中一轮。
|
|
10
|
+
|
|
11
|
+
## 先读这条:任务简报里的命令清单大半是假的
|
|
12
|
+
|
|
13
|
+
执行引擎是 multica 的 daemon,它拼简报时**默认自己是完整的 multica 产品**——
|
|
14
|
+
issue、chat channel、squad、附件、workspace、project,简报里会提到这些。
|
|
15
|
+
**这里一个都没有。**
|
|
16
|
+
|
|
17
|
+
简报里那份 `multica` 命令手册,只有一条在本环境真实可用:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
multica repo checkout <URL>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
其余的 `multica` 子命令敲下去都会被明确拒绝,stderr 上会告诉你这里没有这个东西、
|
|
24
|
+
以及改做什么。那些拒绝信息是给你看的,照着做就行,**不要换个写法重试**。
|
|
25
|
+
|
|
26
|
+
你自己的能力在 `df-agentrt` 上,已经在 PATH 里,不需要定位路径。
|
|
27
|
+
|
|
28
|
+
## 目标环境门禁与地址
|
|
29
|
+
|
|
30
|
+
涉及直接调用 Agent Runtime 服务(例如使用 `agentrt` CLI)时,必须先确认用户要操作的目标环境。用户没有明确说 `local`、本地、`dev`、开发环境或 `prod`、生产环境时,先询问:
|
|
31
|
+
|
|
32
|
+
```text
|
|
33
|
+
请指定目标环境:local(本地)、dev(开发环境)还是 prod(生产环境)?
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
环境一旦选定,本轮所有服务调用都必须保持在同一环境;不能因为连接失败就切换到另一环境,也不能把当前机器所在位置当成目标环境。
|
|
37
|
+
|
|
38
|
+
| 目标环境 | 本地执行时的地址 | 在 dev-k8s 内执行时的地址 |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `local` | `http://127.0.0.1:8141` | 不适用 |
|
|
41
|
+
| `dev` | `https://deepflowagentruntime.dev.deepwisdomai.com` | `http://deepflowagentruntime.deepflow.svc.cluster.local:8141` |
|
|
42
|
+
| `prod` | 尚未配置 | 尚未配置 |
|
|
43
|
+
|
|
44
|
+
地址列描述的是同一目标环境的两种访问方式:本地 CLI 使用 dev Ingress,集群内 Agent 使用 dev Service DNS。确认环境后,用 `AGENTRT_ADDR` 指向该环境的地址;用户明确提供的地址只能覆盖已确认环境的默认地址,若与环境冲突则先停止并澄清。`prod` 目前没有地址,任何 prod 操作都必须停止并说明尚未接入。
|
|
45
|
+
|
|
46
|
+
本地操作 dev 时示例:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
AGENTRT_ADDR=https://deepflowagentruntime.dev.deepwisdomai.com agentrt session ls
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
先请求选定地址的 `GET /healthz`,确认 runtime 可用后再执行操作。健康检查失败时报告该环境不可达,不得静默改用 localhost 或其他环境。
|
|
53
|
+
|
|
54
|
+
`df-agentrt` 的 `session`、`repo`、`events` 等命令操作的是当前 Runtime 会话控制面,不接受 `AGENTRT_ADDR`;不要把当前会话与另一个环境的 Runtime 混用。需要明确操作某个环境的 Runtime 服务时,使用 `agentrt` 并设置对应的 `AGENTRT_ADDR`。
|
|
55
|
+
|
|
56
|
+
## 消息流是交付物本身
|
|
57
|
+
|
|
58
|
+
这个会话的消息流**永久可见**,release 之后也仍然完整可读,而且是被人一行一行读的。
|
|
59
|
+
|
|
60
|
+
所以:**你的输出就是产物。** 不要只说"我改好了"、"详见文件"——把结论、关键改动、
|
|
61
|
+
你判断的依据写进回复。读的人多半不会去翻你的工作目录,很多时候他也翻不了
|
|
62
|
+
(见下面「工作目录会被回收」)。
|
|
63
|
+
|
|
64
|
+
## 没有附件通道
|
|
65
|
+
|
|
66
|
+
任务简报每一轮末尾都会告诉你:要在回复里带文件就跑 `multica attachment upload`。
|
|
67
|
+
**那条指令在这里是错的**,本环境没有附件通道,那个命令会失败。
|
|
68
|
+
|
|
69
|
+
需要交付文件内容时,用文字描述,或者把关键片段直接贴进回复。**不要**写成本地路径链接,
|
|
70
|
+
也不要写得像文件已经送到了——读的人会去找一个根本不存在的附件。
|
|
71
|
+
|
|
72
|
+
## 工作目录:跨轮复用,检出是同级目录
|
|
73
|
+
|
|
74
|
+
- 同一个会话的多轮**复用同一个工作目录**,上一轮留下的文件这一轮还在。
|
|
75
|
+
- `repo add` / `repo checkout` 检出的仓库,落在**你当前工作目录的同级**,不在里面。
|
|
76
|
+
- 目录名取自 URL 的最后一段,**不一定等于应用名**。不要猜,用命令打印出来的绝对路径。
|
|
77
|
+
|
|
78
|
+
## release 之后工作目录会被回收
|
|
79
|
+
|
|
80
|
+
会话 release 之后:消息流仍然可读,**工作目录会被删掉**。
|
|
81
|
+
|
|
82
|
+
所以**不要把唯一的产出留在磁盘上**。重要的结论、生成的内容、分析结果,都要进消息流。
|
|
83
|
+
磁盘是工作区,不是交付区。
|
|
84
|
+
|
|
85
|
+
## 取消是协作式的
|
|
86
|
+
|
|
87
|
+
被取消时你不会被当场杀掉:状态先变成 `cancelled`,你会收到停止的请求,
|
|
88
|
+
然后有时间收尾。收到取消请求就**尽快收尾并把已有的结论说出来**,
|
|
89
|
+
不要假装无事发生继续跑,也不要因为被取消就什么都不留下。
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 命令总览
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
本会话(不需要会话 id,它自己知道是哪个)
|
|
97
|
+
df-agentrt session info 你是谁:provider、model、工作目录、仓库,
|
|
98
|
+
以及上一轮的对话历史有没有续上
|
|
99
|
+
df-agentrt session turns 这个会话到目前为止的每一轮
|
|
100
|
+
df-agentrt events [--after N] 消息流,一行一条
|
|
101
|
+
df-agentrt repo list 本会话可以检出哪些仓库
|
|
102
|
+
df-agentrt repo search <应用名> 按应用名找仓库
|
|
103
|
+
df-agentrt repo add <url|应用代码> 加一个仓库进来并当场检出
|
|
104
|
+
df-agentrt msg cancel 请求停掉当前这一轮
|
|
105
|
+
|
|
106
|
+
别的会话(必须显式给会话 id)
|
|
107
|
+
df-agentrt session ls 这个 runtime 上的会话
|
|
108
|
+
df-agentrt session get <会话id> 某个会话的完整信息
|
|
109
|
+
df-agentrt session create ... 新建会话 💰
|
|
110
|
+
df-agentrt msg send <会话id> <文本> 给别的会话排一轮 💰
|
|
111
|
+
|
|
112
|
+
运行时
|
|
113
|
+
df-agentrt ops runtimes 执行引擎注册了哪些、还活着哪些
|
|
114
|
+
df-agentrt ops orphans 记录和现实哪里对不上(只读)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## 业务 metadata 与软范围查询
|
|
118
|
+
|
|
119
|
+
Runtime Session 可以携带业务方自定义的 JSON metadata。基础服务只约定顶层的 source、
|
|
120
|
+
query_keys 和 data:前两个用于可选的软范围查询,data 由业务方自行组织。
|
|
121
|
+
|
|
122
|
+
需要由 CLI 创建 Session 时,把完整对象传给 session create:
|
|
123
|
+
|
|
124
|
+
df-agentrt session create \
|
|
125
|
+
--provider claude \
|
|
126
|
+
--metadata '{"source":"workbench","query_keys":["account:u123"],"data":{"project":"orders"}}'
|
|
127
|
+
|
|
128
|
+
查询已有 Session 时可按同一范围过滤:
|
|
129
|
+
|
|
130
|
+
df-agentrt session ls \
|
|
131
|
+
--metadata-source workbench \
|
|
132
|
+
--metadata-query-key account:u123
|
|
133
|
+
df-agentrt session get <session-id> \
|
|
134
|
+
--metadata-source workbench \
|
|
135
|
+
--metadata-query-key account:u123
|
|
136
|
+
|
|
137
|
+
query_keys 可以包含多个标识;"*" 表示显式共享,匹配任意来源和查询标识;不提供过滤
|
|
138
|
+
参数仍保持历史上的全量行为。metadata 是查询范围,不是权限控制。标准 Task 流程中,
|
|
139
|
+
deepflow-task-driver 会把 Task metadata 原样透传到它创建的 Session,Agent 不需要重新拼接;
|
|
140
|
+
Runtime 也不会从登录身份或当前会话自动推断业务范围。
|
|
141
|
+
|
|
142
|
+
当前 session info、session get 和 session ls 的人类可读输出不会打印 metadata 原文,
|
|
143
|
+
不要把输出中没有 metadata 理解成 Session 没有 metadata。需要核对原值时读取 Runtime API 的
|
|
144
|
+
JSON 响应;CLI 过滤仍然可以正常使用。
|
|
145
|
+
|
|
146
|
+
💰 这两条会**真的跑起来一个 agent**,花的是真钱。而且新建的会话**不会自己结束**——
|
|
147
|
+
它会一直占着一个工作目录,直到有人显式 release 它。确认你真的需要另一个会话再用,
|
|
148
|
+
多数时候你要的只是自己把活干完。
|
|
149
|
+
|
|
150
|
+
创建结果不确定时,用稳定 key 重试同一次创建:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
df-agentrt session create --provider claude --idempotency-key cli:ticket-42
|
|
154
|
+
df-agentrt session create --provider claude --idempotency-key cli:ticket-42
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
两次会返回同一个 id。新的创建意图必须换 key,不要在每次重试前重新生成。key 在当前 runtime
|
|
158
|
+
数据库内全局有效、区分大小写,非空时最多 256 字节且只能是无空白、无逗号的可见 ASCII;不传
|
|
159
|
+
key 时每次新建。同 key 只保留首次成功写入的配置,released 状态也会原样返回;物理删除 Session
|
|
160
|
+
后该 key 的保留随之终止。
|
|
161
|
+
|
|
162
|
+
`session info` 值得一开始就跑:它会告诉你**上一轮的对话历史有没有续上**。
|
|
163
|
+
没续上的话,文件都在,但你读不到之前说过什么——这时候先看 `session turns` 和
|
|
164
|
+
`events`,别凭空假设自己记得。
|
|
165
|
+
|
|
166
|
+
`ops runtimes` 是「某一轮卡住不动」时第一个该问的问题:一个正在思考的 daemon,
|
|
167
|
+
和一个一小时前就被杀掉的 daemon,从会话那边看起来一模一样。
|
|
168
|
+
|
|
169
|
+
### 有三件事不归你做
|
|
170
|
+
|
|
171
|
+
`session release`、`session rm`、`ops orphans --fix` **不要用**。它们都是替别人做决定:
|
|
172
|
+
回收工作目录由控制面决定,删会话会抹掉永久可见的消息流,判死滞留轮次动的是别的会话。
|
|
173
|
+
二进制不会拦你——它会照做,所以这条只能靠你守住。
|
|
174
|
+
|
|
175
|
+
发现某个会话像是卡住了、或者某个工作目录该回收了,**在回复里说出来**,
|
|
176
|
+
让读的人去处理。这比你直接动手有用——你只看得到这一轮,他看得到全局。
|
|
177
|
+
|
|
178
|
+
### 退出码
|
|
179
|
+
|
|
180
|
+
| 码 | 含义 | 该怎么办 |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| 0 | 成功 | —— |
|
|
183
|
+
| 1 | 请求发出去了,但失败了 | 看 stderr,它写清了原因 |
|
|
184
|
+
| 2 | 命令行写错了,一个请求都没发 | 改命令 |
|
|
185
|
+
| 3 | 环境/部署不对 | **不是你的错,重试没用**,在回复里说明 |
|
|
186
|
+
|
|
187
|
+
## 添加代码仓库
|
|
188
|
+
|
|
189
|
+
`repo list` / `search` / `add` 的详细用法、`--ref` 的限制、以及三个容易做错的地方,
|
|
190
|
+
见 `df-agentrt-repo` skill。一句话版本:**不要自己拼 `multica repo checkout` 去检出刚加的
|
|
191
|
+
仓库**,daemon 的白名单按 URL 逐字符匹配,你手敲的那个字符串未必是服务端存下来的那个。
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: df-agentrt-repo
|
|
3
|
+
description: 任务进行中发现需要另一个代码仓库时使用。查看本会话已有的仓库、按应用名搜索仓库、把新仓库加进来并当场检出。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 中途添加代码仓库
|
|
7
|
+
|
|
8
|
+
会话创建时定下的配置里,只有**代码仓库**这一项是可以在任务进行中追加的。
|
|
9
|
+
|
|
10
|
+
你可能在分析到一半时才发现答案不在手上这几个仓库里——这时不需要中断任务回报、
|
|
11
|
+
等人重建会话,用 `df-agentrt` 自己把仓库加进来,一个回合内就能继续。
|
|
12
|
+
|
|
13
|
+
`df-agentrt` 已经在 PATH 上,不需要定位路径。
|
|
14
|
+
|
|
15
|
+
## 已经有哪些仓库
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
df-agentrt repo list
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
每行一个仓库:URL、`@分支`(如果固定了分支)、括号里是说明。
|
|
22
|
+
**先跑这个**——需要的仓库很可能已经在列表里,那就只差一个检出:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
multica repo checkout <上面列出的 URL>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 找仓库
|
|
29
|
+
|
|
30
|
+
知道应用叫什么、不知道代码在哪:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
df-agentrt repo search 结算服务
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
输出三列,用 Tab 分隔:**应用代码**、应用名、仓库地址。第一列是下一步要用的参数。
|
|
37
|
+
|
|
38
|
+
搜不到不是失败。换一个更短的词再试,或者你要是本来就知道 clone 地址,跳过这步。
|
|
39
|
+
|
|
40
|
+
## 加进来
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
df-agentrt repo add <应用代码或 clone 地址> [...]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
参数里带 `://` 或 `@` 的当作 clone 地址,其余当作应用代码去查。两种可以混在一条命令里。
|
|
47
|
+
|
|
48
|
+
要固定分支:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
df-agentrt repo add https://git.example.com/g/settle --ref release/2026-09
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`--ref` 一次只能配一个 clone 地址。多个仓库共用一个分支名几乎都是写错了,
|
|
55
|
+
真要这么做就分成几条命令。
|
|
56
|
+
|
|
57
|
+
**这条命令会把仓库检出,不需要再跑别的。** stdout 上每行是一个检出目录的绝对路径,
|
|
58
|
+
直接拿去读文件。
|
|
59
|
+
|
|
60
|
+
## 三件容易做错的事
|
|
61
|
+
|
|
62
|
+
**不要自己拼 `multica repo checkout` 去检出刚加的仓库。** daemon 的白名单按 URL
|
|
63
|
+
**逐字符**匹配,你手敲的地址少一个 `.git`、多一个尾斜杠,就是另一个仓库,
|
|
64
|
+
会得到「repo is not configured」——而 `repo list` 里明明有它。`repo add` 用的是服务端存下来的
|
|
65
|
+
那个字符串,所以它检出得了,你重新敲一遍的不一定。
|
|
66
|
+
|
|
67
|
+
**仓库只能加不能删。** 当前回合可能正在某个仓库里工作,删掉就把这个回合弄坏了。
|
|
68
|
+
|
|
69
|
+
**重复添加是安全的。** 已经有了就不会重复加,但仍然会做一次检出——
|
|
70
|
+
「在列表里」和「在磁盘上」是两回事。
|
|
71
|
+
|
|
72
|
+
## 命令失败了怎么办
|
|
73
|
+
|
|
74
|
+
stderr 上的话是给你看的,照着做:
|
|
75
|
+
|
|
76
|
+
- 说「retrying will not help」——环境问题,不是参数问题,别换个写法再试,直接在回复里说明;
|
|
77
|
+
- 说「remain configured」——仓库加上了,只是检出没成功,可以用 `multica repo checkout <URL>` 重试;
|
|
78
|
+
- 其余的错误信息来自服务端,已经写清楚了原因和下一步。
|
|
79
|
+
|
|
80
|
+
## 加完之后
|
|
81
|
+
|
|
82
|
+
检出目录和你当前的工作目录是同级的。用 `repo add` 打印出来的绝对路径访问,
|
|
83
|
+
不要猜目录名——仓库目录名来自 URL 最后一段,不一定等于应用名。
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: df-task
|
|
3
|
+
description: 在一次 Run 里用 df-task 读写 DeepFlow Task 事实日志 —— 读本 Task 的历史事实、发布产物引用、写关键摘要、求助、主张本 Run 目标达成或无法完成;调度智能体另外用它写唤起意图、等待依据、交给人、裁决与 Run 终止。本 Skill 不负责启动或停止 Run(那是 df-agentrt 与推进器的事),不负责智能体定义(那在 deepflow-agent-ctrl),也不提供任何修改或删除事实的手段。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# df-task
|
|
7
|
+
|
|
8
|
+
`df-task` 是 DeepFlow Task 事实日志的命令行入口。Task 是一件工作的身份,它下面挂着一本**只追加**的事实日志:谁在什么时候写下了什么。**没有状态字段,也没有状态机** —— 「这件工作到哪一步了」是从这本日志里读出来的,不是查出来的。
|
|
9
|
+
|
|
10
|
+
服务地址取自 `DF_TASK_BASE_URL`,默认 `http://127.0.0.1:8090`。写事实的身份取自 `DF_TASK_ACTOR_KIND` 与 `DF_TASK_ACTOR_ID`,由 runtime 在起进程时注入 —— **不要自己改这两个环境变量**,身份决定了你能写哪些事实。
|
|
11
|
+
|
|
12
|
+
## 任务描述
|
|
13
|
+
|
|
14
|
+
每轮工作先用 `df-task get "$DF_TASK_ID" --json` 读取 `description` 与 `description_version`。标题是简短名称,描述是当前需求,首条消息仅是历史事实;不能用首条消息替代描述。汇报前再次核对版本,若描述变化需重新核对范围与验收条件。
|
|
15
|
+
|
|
16
|
+
## 目标环境门禁与地址
|
|
17
|
+
|
|
18
|
+
每次调用服务前,必须先确认用户要操作的目标环境。在推进器拉起的 Run 里按下文「Run 内的目标环境」确定,不询问。其他情况下,用户没有明确说 `local`、本地、`dev`、开发环境或 `prod`、生产环境时,先询问:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
请指定目标环境:local(本地)、dev(开发环境)还是 prod(生产环境)?
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
环境一旦选定,本轮所有服务调用都必须保持在同一环境;不能因为连接失败就切换到另一环境,也不能把当前机器所在位置当成目标环境。
|
|
25
|
+
|
|
26
|
+
| 目标环境 | 本地执行时的地址 | 在 dev-k8s 内执行时的地址 |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `local` | `http://127.0.0.1:8090` | 不适用 |
|
|
29
|
+
| `dev` | `https://deepflowtask.dev.deepwisdomai.com` | `http://deepflowtask.deepflow.svc.cluster.local:8090` |
|
|
30
|
+
| `prod` | 尚未配置 | 尚未配置 |
|
|
31
|
+
|
|
32
|
+
地址列描述的是同一目标环境的两种访问方式:本地 CLI 使用 dev Ingress,集群内 Agent 使用 dev Service DNS。确认环境后,可以用用户明确提供的 `--base-url` 覆盖该环境的默认地址,但该地址必须属于已选环境;如果地址与环境冲突,先停止并澄清,不能用它绕过环境门禁。`prod` 目前没有地址,任何 prod 操作都必须停止并说明尚未接入。
|
|
33
|
+
|
|
34
|
+
本地操作 dev 时示例:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
df-task --base-url https://deepflowtask.dev.deepwisdomai.com facts "$DF_TASK_ID" --json
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Run 内的目标环境
|
|
41
|
+
|
|
42
|
+
`DF_TASK_ID`、`DF_RUN_ID`、`DF_TASK_ACTOR_KIND` 都非空时,你运行在推进器拉起的 Run 里,没有用户可以询问。此时目标环境由部署决定:用注入的 `DF_TASK_BASE_URL` 对照上表反查所属环境,例如 `http://deepflowtask.deepflow.svc.cluster.local:8090` 即 `dev`。每一轮、每个 Run 都按同一规则确定,不需要也不应该等待任何人确认。
|
|
43
|
+
|
|
44
|
+
反查不到任何环境、地址属于 `prod`,或指令要求操作的环境与反查结果不一致时,停止,不调用服务、不改用其他地址,在最终回复里说明注入地址和冲突原因。推进器会照常记录本次执行结束,交给下一轮调度或人处理。
|
|
45
|
+
|
|
46
|
+
不在 Run 里时,只有在用户明确选择 `dev` 且 `DF_TASK_BASE_URL` 确认属于 dev 时,才可以复用它;用户选择 `local` 时必须忽略该值并使用 `http://127.0.0.1:8090`。用户没有先选环境都不能执行请求。
|
|
47
|
+
|
|
48
|
+
先用 `GET /healthz` 验证选定地址,再执行读写操作。健康检查失败时报告该环境不可达,不得静默改用 localhost 或其他环境。
|
|
49
|
+
|
|
50
|
+
下面的示例还用到两个变量,同样由 runtime 注入,同样不要自己编:`DF_TASK_ID` 是你这次执行所属的 Task,`DF_RUN_ID` 是你自己这个 Run 的标识(写事实时 payload 里的 `run_id` 填它)。如果它们是空的,说明这次执行不是由推进器兑现唤起起来的 —— 别猜一个填进去,写一条 `summary` 说明情况。
|
|
51
|
+
|
|
52
|
+
**在 Run 里一律加 `--json`。** 不加 `--json` 的输出是给人看的排版,字段随时会调整。
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# 读本 Task 的全部事实
|
|
56
|
+
df-task facts "$DF_TASK_ID" --json
|
|
57
|
+
|
|
58
|
+
# 只读某几类,或从某个序号往后读
|
|
59
|
+
df-task facts "$DF_TASK_ID" --types user_message,artifact_published --json
|
|
60
|
+
df-task facts "$DF_TASK_ID" --after 128 --json
|
|
61
|
+
|
|
62
|
+
# 追加一条事实:payload 写成 JSON 文件再传
|
|
63
|
+
# 注意 heredoc 的标记不加引号,加了引号 $DF_RUN_ID 就不会展开
|
|
64
|
+
cat > /tmp/artifact.json <<JSON
|
|
65
|
+
{"run_id":"$DF_RUN_ID","kind":"diff","ref":"abc1234def5678","title":"登录按钮溢出修复"}
|
|
66
|
+
JSON
|
|
67
|
+
df-task append "$DF_TASK_ID" --type artifact_published --file /tmp/artifact.json --json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 业务 metadata 与软范围查询
|
|
71
|
+
|
|
72
|
+
Task 可以携带业务方自定义的 JSON metadata。基础服务只约定顶层的
|
|
73
|
+
`source`、`query_keys` 和 `data`:前两个用于可选的软范围查询,`data` 完全由业务方组织。
|
|
74
|
+
例如:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
df-task create \
|
|
78
|
+
--title '订单分析' \
|
|
79
|
+
--metadata '{"source":"workbench","query_keys":["account:u123"],"data":{"project":"orders"}}' \
|
|
80
|
+
--json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`--metadata` 必须是 JSON 对象;没有 metadata 时服务保存 `{}`,不会改变原有流程。创建、
|
|
84
|
+
列表和单Task读取会返回 metadata。事实读取也支持同一范围过滤:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
SCOPE_SOURCE=workbench
|
|
88
|
+
SCOPE_KEY=account:u123
|
|
89
|
+
|
|
90
|
+
df-task ls \
|
|
91
|
+
--metadata-source "$SCOPE_SOURCE" \
|
|
92
|
+
--metadata-query-key "$SCOPE_KEY" \
|
|
93
|
+
--json
|
|
94
|
+
df-task get "$DF_TASK_ID" \
|
|
95
|
+
--metadata-source "$SCOPE_SOURCE" \
|
|
96
|
+
--metadata-query-key "$SCOPE_KEY" \
|
|
97
|
+
--json
|
|
98
|
+
df-task facts "$DF_TASK_ID" \
|
|
99
|
+
--metadata-source "$SCOPE_SOURCE" \
|
|
100
|
+
--metadata-query-key "$SCOPE_KEY" \
|
|
101
|
+
--json
|
|
102
|
+
df-task stream \
|
|
103
|
+
--metadata-source "$SCOPE_SOURCE" \
|
|
104
|
+
--metadata-query-key "$SCOPE_KEY" \
|
|
105
|
+
--json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
查询规则:
|
|
109
|
+
|
|
110
|
+
- 同时提供 `source` 和 `query_key` 时,Task 必须匹配来源和查询标识;只提供其中一个时只按该条件过滤。`query_keys` 包含 `"*"` 的显式共享Task例外于这两个条件。
|
|
111
|
+
- `query_keys` 可以包含多个标识;`"*"` 表示显式共享,匹配任意查询范围。
|
|
112
|
+
- 不提供过滤参数仍然是历史上的全量查询。业务上下文存在时才携带过滤参数,不要把它当成权限边界。
|
|
113
|
+
- 先从Task响应的 metadata 读取 `source` 和 `query_keys`,再把当前业务上下文中的具体 key 传给后续查询;不要从 `data` 中猜测过滤字段。
|
|
114
|
+
|
|
115
|
+
metadata 只影响读请求的范围。`append`、`dispatch`、`wait`、`handoff` 和 `title` 仍按明确的
|
|
116
|
+
Task ID 操作,不支持 metadata 过滤参数;事实服务不会根据 metadata 做鉴权。
|
|
117
|
+
|
|
118
|
+
命令不存在时,本项目源码可用的话在 `deepflow-task/` 下运行 `make install-cli`,它把 `df-task` 装到 `$HOME/.local/bin`。**注意不要把 runtime 的地址填成 Task 服务的地址** —— `df-agentrt` 和 `df-task` 是两个服务、两个端口、两套授权。
|
|
119
|
+
|
|
120
|
+
## 读日志
|
|
121
|
+
|
|
122
|
+
1. 先 `df-task facts "$DF_TASK_ID" --json` 通读一遍,搞清这件工作已经发生过什么
|
|
123
|
+
2. 关心产物就加 `--types artifact_published`;关心人说了什么就加 `--types user_message`
|
|
124
|
+
3. 产物事实里存的是**引用坐标,不是内容**。要看 diff、spec、MR 的正文,拿着 `ref` 自己去外部系统取
|
|
125
|
+
4. 要分页往后读就用上一页返回的 `next_after_seq` 当下一次的 `--after`
|
|
126
|
+
|
|
127
|
+
序号有空洞,且落库顺序不保证与序号顺序一致。一次读不完就接着读,不要假设「序号连续就是读全了」。
|
|
128
|
+
|
|
129
|
+
## 任务 Run 可以写什么
|
|
130
|
+
|
|
131
|
+
| 命令 | 落成哪条事实 | 什么时候写 |
|
|
132
|
+
| --- | --- | --- |
|
|
133
|
+
| `df-task append <task-id> --type artifact_published --file p.json` | `artifact_published` | 产出了别人要用的东西:diff、spec、测试结果、MR。只写引用坐标 |
|
|
134
|
+
| `df-task append <task-id> --type summary --file p.json` | `summary` | 有一个结论值得留给下一个 Run,或想说明「还需要做 X」 |
|
|
135
|
+
| `df-task append <task-id> --type help_requested --file p.json` | `help_requested` | 卡住了,需要人或调度智能体给一个答案 |
|
|
136
|
+
| `df-task append <task-id> --type run_outcome --file p.json` | `run_outcome` | 本 Run 目标达成或无法完成,附结论与理由 |
|
|
137
|
+
|
|
138
|
+
四条都**不会触发下一轮调度**。真正触发下一轮的是「唤起结束」,它由推进器在观察到本次执行终态后写下 —— 所以你正常结束、异常崩溃,下一轮调度都照样会起来。
|
|
139
|
+
|
|
140
|
+
**`run_outcome` 只是你的主张,不是这件工作的结论。** 调度智能体完全可以不采信并要求返工。
|
|
141
|
+
|
|
142
|
+
**想派生一条支线,就在 `summary` 里写清「还需要做 X」**,下一轮调度会看到。不要试图自己开 Run。
|
|
143
|
+
|
|
144
|
+
## 调度 Run 可以写什么
|
|
145
|
+
|
|
146
|
+
| 命令 | 落成哪条事实 | 什么时候写 |
|
|
147
|
+
| --- | --- | --- |
|
|
148
|
+
| `df-task dispatch <task-id> --agent <name> --instruction <text>` | `dispatch_intent`(`mode` 为 `new_run`) | 把一块工作派给某个智能体,开一个新 Run |
|
|
149
|
+
| `df-task dispatch <task-id> --agent <name> --instruction <text> --run <run-id>` | `dispatch_intent`(`mode` 为 `message`) | 往一个还活着的 Run 投一条消息 |
|
|
150
|
+
| `df-task wait <task-id> --on <what> --reason <text>` | `waiting_reason` | 该派的都派了,在等人回话或等一条外部结果 |
|
|
151
|
+
| `df-task handoff <task-id> --ask <text>` | `handoff_to_human` | 把球交给人。既用于「都做完了请验收」,也用于「这一步我做不了请你做」 |
|
|
152
|
+
| `df-task append <task-id> --type adjudication --file p.json` | `adjudication` | 对某条事实下裁决,`subject` 是那条事实的序号 |
|
|
153
|
+
| `df-task append <task-id> --type run_terminated --file p.json` | `run_terminated` | **已经用 `df-agentrt` 停完 Run 之后**,记录这个既成事实 |
|
|
154
|
+
|
|
155
|
+
前四行是语法糖,落库的事实类型见中间那一列 —— 读日志时你看到的是 `dispatch_intent`,不是 `dispatch`。各列字段清单见 `references/fact-types.md`。
|
|
156
|
+
|
|
157
|
+
**每一轮至少写一条。** 一轮调度什么都不写,这个 Task 就会静默停住 —— 那是最坏的失效模式。无事可做不是理由:无事可做就写 `wait` 或 `handoff`。
|
|
158
|
+
|
|
159
|
+
`dispatch` 写完不等于 Run 起来了。**你写完就该结束**,真正拉起进程的是推进器。
|
|
160
|
+
|
|
161
|
+
停 Run 要先用 `df-agentrt` 停并确认停住了,再写 `run_terminated` 记录。顺序反了就会留下一条假事实。
|
|
162
|
+
|
|
163
|
+
## 职责边界
|
|
164
|
+
|
|
165
|
+
- **本 Skill 不启动、不停止任何 Run。** 起 Run 由推进器兑现唤起意图,停 Run 用 `df-agentrt`
|
|
166
|
+
- **没有修改和删除事实的命令**,因为 API 里就没有。写错了就再写一条把它说清楚
|
|
167
|
+
- **不要在 payload 里塞产物正文。** 日志是路牌不是档案馆,只放引用坐标
|
|
168
|
+
- **不查智能体正在干什么。** 那是 runtime 侧的 transcript,用 `df-agentrt` 看
|
|
169
|
+
- **越权会拿到 `403` 且什么都不落库。** 拿到 `403` 说明这条事实不该由你写,不要换个类型重试,写一条 `summary` 或 `help_requested` 说明情况
|
|
170
|
+
|
|
171
|
+
## 输出与错误
|
|
172
|
+
|
|
173
|
+
`--json` 下 stdout 是服务端原样返回的 JSON。退出码只有三个:`0` 成功、`1` 网络或服务端失败、`2` 本地参数无效。**参数错误不会发出任何请求**,所以拿到 `2` 时日志里一定没有任何痕迹。
|
|
174
|
+
|
|
175
|
+
追加成功返回那条事实,含它的 `seq`。`--idempotency-key` 重复提交同一个键时返回**已存在的那条事实**,HTTP 状态是 `200` 而不是 `201` —— 这不是错误,重试是安全的。
|
|
176
|
+
|
|
177
|
+
各类事实的字段清单见 `references/fact-types.md`,可直接抄改的 payload 样例在 `assets/payload-examples/`。
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 事实类型与 payload 字段
|
|
2
|
+
|
|
3
|
+
一共十六种事实。**类型决定语义,身份决定谁能写它。** 服务端只做浅校验:必填字段在不在、枚举值对不对,不校验内容是否合理。
|
|
4
|
+
|
|
5
|
+
## 外部输入(人与外部系统写,**触发下一轮调度**)
|
|
6
|
+
|
|
7
|
+
| 类型 | 谁写 | 必填 | 可选 |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| `user_message` | 人 | `text` | —— |
|
|
10
|
+
| `external_result` | 外部系统 | `source`、`ref`、`result` | —— |
|
|
11
|
+
|
|
12
|
+
对求助的回答、对产物的意见、对裁决的确认,全都是 `user_message`,没有专门的类型。
|
|
13
|
+
|
|
14
|
+
## 人工任务管理(不触发调度)
|
|
15
|
+
|
|
16
|
+
`task_lifecycle` 仅 human 可写,必填 `action`:`complete`、`archive`、`delete`、`reopen`。删除是移入回收站,事实记录保留。此记录不取消执行。
|
|
17
|
+
|
|
18
|
+
## 任务 Run 写的(都**不触发**下一轮调度)
|
|
19
|
+
|
|
20
|
+
| 类型 | 必填 | 可选 | 说明 |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `artifact_published` | `run_id`、`kind`、`ref` | `title` | `ref` 是外部可验证的引用坐标(commit SHA、MR 地址…)。`kind` 决定界面怎么渲染、别的智能体怎么解读。`title` 只给人看 |
|
|
23
|
+
| `summary` | `run_id`、`text` | —— | 留给下一个 Run 的结论。想派生支线就写在这里 |
|
|
24
|
+
| `help_requested` | `run_id`、`question`、`blocking` | —— | `blocking` 是布尔值:不给答案就没法继续吗 |
|
|
25
|
+
| `run_outcome` | `run_id`、`result` | `reason` | `result` 只能是 `reached` 或 `unreachable`。**只是主张,不是 Run 终止** |
|
|
26
|
+
|
|
27
|
+
## 调度 Run 写的(都**不触发**下一轮调度)
|
|
28
|
+
|
|
29
|
+
| 类型 | 必填 | 可选 | 说明 |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| `dispatch_intent` | `target_run_id`、`agent`、`instruction`、`mode` | —— | `mode` 是 `new_run` 或 `message`。用 `df-task dispatch` 更省事,它会替你填这四个字段 |
|
|
32
|
+
| `waiting_reason` | `waiting_on`、`reason` | —— | 给人和给下一轮调度的上下文,**不是推进器的门** |
|
|
33
|
+
| `handoff_to_human` | `ask` | `assignee` | 交球和派活是同一条事实,区别只在 `ask` 的内容 |
|
|
34
|
+
| `adjudication` | `subject`、`verdict` | `reason` | `subject` 是被裁决那条事实的**序号**(数字,不是字符串) |
|
|
35
|
+
| `run_terminated` | `run_id`、`confirmed_status` | —— | 已经停完并确认之后记录的既成事实 |
|
|
36
|
+
|
|
37
|
+
## 推进器写的(智能体写会拿 `403`)
|
|
38
|
+
|
|
39
|
+
唤起生命周期是整套设计里唯一不依赖智能体配合的推进信号,所以**只有推进器能写**。列在这里是为了让你读日志时认得它们。
|
|
40
|
+
|
|
41
|
+
| 类型 | 必填 | 可选 | 含义 |
|
|
42
|
+
| --- | --- | --- | --- |
|
|
43
|
+
| `invocation_started` | `run_id`、`run_kind` | `intent_seq`、`input_watermark` | 推进器决定去启动,此时还没调用 runtime |
|
|
44
|
+
| `invocation_accepted` | `run_id`、`session_id`、`invocation_id` | —— | runtime 受理了 |
|
|
45
|
+
| `invocation_ended` | `run_id`、`invocation_id`、`terminal_status` | —— | **唯一由推进器写的触发事实** |
|
|
46
|
+
| `attempt_failed` | `watermark`、`reason` | `intent_seq` | 推进失败 |
|
|
47
|
+
|
|
48
|
+
**「有 started 没有 accepted」是合法的中间状态**,含义是「正在启动,结果未知」。读日志时不要把它当成异常 —— 推进器会靠幂等键重投把它推进到 accepted。`run_kind` 只能是 `scheduler` 或 `task`;只有调度唤起带 `input_watermark`。
|