@my-life-buddies/buddy-runtime 0.0.2 → 0.1.0
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 +121 -21
- package/dist/conversation/agent.d.ts +8 -4
- package/dist/conversation/agent.d.ts.map +1 -1
- package/dist/conversation/agent.js +38 -31
- package/dist/conversation/agent.js.map +1 -1
- package/dist/conversation/agentMessageLLMMessageConverter.d.ts +8 -0
- package/dist/conversation/agentMessageLLMMessageConverter.d.ts.map +1 -0
- package/dist/conversation/agentMessageLLMMessageConverter.js +48 -0
- package/dist/conversation/agentMessageLLMMessageConverter.js.map +1 -0
- package/dist/conversation/convert.d.ts +11 -11
- package/dist/conversation/convert.d.ts.map +1 -1
- package/dist/conversation/convert.js +51 -29
- package/dist/conversation/convert.js.map +1 -1
- package/dist/conversation/history.d.ts +14 -14
- package/dist/conversation/history.d.ts.map +1 -1
- package/dist/conversation/history.js +19 -21
- package/dist/conversation/history.js.map +1 -1
- package/dist/conversation/index.d.ts +26 -25
- package/dist/conversation/index.d.ts.map +1 -1
- package/dist/conversation/index.js +106 -104
- package/dist/conversation/index.js.map +1 -1
- package/dist/conversation/mlbMessageAgentMessageConverter.d.ts +36 -0
- package/dist/conversation/mlbMessageAgentMessageConverter.d.ts.map +1 -0
- package/dist/conversation/mlbMessageAgentMessageConverter.js +224 -0
- package/dist/conversation/mlbMessageAgentMessageConverter.js.map +1 -0
- package/dist/conversation/readMLBMessages.d.ts +29 -0
- package/dist/conversation/readMLBMessages.d.ts.map +1 -0
- package/dist/conversation/readMLBMessages.js +86 -0
- package/dist/conversation/readMLBMessages.js.map +1 -0
- package/dist/conversation/writeMLBMessage.d.ts +62 -0
- package/dist/conversation/writeMLBMessage.d.ts.map +1 -0
- package/dist/conversation/writeMLBMessage.js +212 -0
- package/dist/conversation/writeMLBMessage.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/mlbClient.d.ts +17 -6
- package/dist/mlbClient.d.ts.map +1 -1
- package/dist/mlbClient.js +58 -4
- package/dist/mlbClient.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +14 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/dataAccess.d.ts +48 -0
- package/dist/tools/dataAccess.d.ts.map +1 -0
- package/dist/tools/dataAccess.js +131 -0
- package/dist/tools/dataAccess.js.map +1 -0
- package/dist/types.d.ts +48 -14
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
MLB 搭子运行时。基于 [`@earendil-works/pi-agent-core`](https://www.npmjs.com/package/@earendil-works/pi-agent-core) 构建,负责搭子与 MLB 平台之间的全部交互:订阅事件流、拉取消息、驱动模型、写回回复、推送在线状态。开发者只需提供搭子的配置。
|
|
4
4
|
|
|
5
|
-
## 安装
|
|
5
|
+
## 1. 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @my-life-buddies/buddy-runtime
|
|
8
|
+
npm install @my-life-buddies/buddy-runtime
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
要求 Node.js ≥ 22.19。
|
|
12
12
|
|
|
13
|
-
## 快速开始
|
|
13
|
+
## 2. 快速开始
|
|
14
14
|
|
|
15
15
|
```
|
|
16
16
|
my-buddy/
|
|
@@ -58,9 +58,9 @@ await BuddyServer.start({
|
|
|
58
58
|
|
|
59
59
|
完整示例见 [examples/aunt-tu/](examples/aunt-tu/)。
|
|
60
60
|
|
|
61
|
-
## API
|
|
61
|
+
## 3. API
|
|
62
62
|
|
|
63
|
-
### `BuddyServer.start(options)`
|
|
63
|
+
### 3.1 `BuddyServer.start(options)`
|
|
64
64
|
|
|
65
65
|
启动搭子进程,连接平台事件流。返回 `{ stop(): Promise<void> }`。
|
|
66
66
|
|
|
@@ -69,7 +69,7 @@ await BuddyServer.start({
|
|
|
69
69
|
| `options.model` | `string`,必填 | 模型 id,取值见平台 `GET /cli/models`。进程内所有会话共用。没填,或 id 在运行时内置的模型目录中不存在时,启动失败 |
|
|
70
70
|
| `options.buddy` | `(conversation: Conversation) => BuddyOptions \| Promise<BuddyOptions>` | 搭子配置工厂。每场会话在第一条消息到达时调用一次 |
|
|
71
71
|
|
|
72
|
-
### `BuddyOptions`
|
|
72
|
+
### 3.2 `BuddyOptions`
|
|
73
73
|
|
|
74
74
|
配置的形状与字段名与 pi-agent-core 的 `AgentOptions` / `AgentState` 一致,签名请参考 pi 的文档。
|
|
75
75
|
|
|
@@ -84,15 +84,15 @@ type BuddyOptions =
|
|
|
84
84
|
|
|
85
85
|
| 字段 | 说明 |
|
|
86
86
|
|---|---|
|
|
87
|
-
| `initialState.systemPrompt` |
|
|
87
|
+
| `initialState.systemPrompt` | 系统提示。静态内容;每回合变化的信息不应写在这里。工程目录下有 `resources/` 时,运行时在末尾追加资料清单 |
|
|
88
88
|
| `initialState.tools` | 工具列表,类型为 pi 的 `AgentTool`。`label` 为必填,用作用户可见的状态行文案(空字符串表示不显示);`execute` 返回值的 `details` 为必填(可为 `undefined`);执行失败应直接抛出异常。工具名不得与内置工具或其他工具重复。先单独声明为 `AgentTool<typeof 参数 schema>` 再放入数组,`execute` 的参数才有类型;直接写在数组里时参数类型为 `unknown` |
|
|
89
89
|
| `initialState.thinkingLevel` | 思考级别,默认 `off`。模型不支持的级别在发请求前就近换成支持的一档。显式设了模型不支持的级别时,每场会话建立时打一条 warn |
|
|
90
|
-
| `transformContext` |
|
|
90
|
+
| `transformContext` | 历史裁剪。入参是这场会话完整的 Agent 历史,平台交代的场合也在其中,消息从哪来、长什么样见下方「4. 会话历史」一节;返回值只用于这一次模型请求,不改动历史;抛出异常时使用原历史 |
|
|
91
91
|
| `beforeToolCall` / `afterToolCall` / `shouldStopAfterTurn` / `prepareNextTurnWithContext` / `thinkingBudgets` / `toolExecution` | 原样传递给 pi |
|
|
92
92
|
|
|
93
93
|
密钥、会话历史、会话标识与插话策略由运行时统一管理,不对开发者开放。模型通过 `BuddyServer.start` 的 `model` 选择。
|
|
94
94
|
|
|
95
|
-
### `Conversation`:给开发者调用的方法
|
|
95
|
+
### 3.3 `Conversation`:给开发者调用的方法
|
|
96
96
|
|
|
97
97
|
工厂拿到的对象。上面的属性和方法由开发者在代码里调用,不会注册给模型;要让模型用到,开发者自己包成工具放进 `initialState.tools`,见下方 `remember` 的例子。
|
|
98
98
|
|
|
@@ -105,6 +105,9 @@ interface Conversation {
|
|
|
105
105
|
write(key: string, text: string): Promise<void>; // 覆盖写一条
|
|
106
106
|
delete(key: string): Promise<void>; // 删一条,删不存在的也算成功
|
|
107
107
|
};
|
|
108
|
+
readonly dataAccess: {
|
|
109
|
+
query(request: { datasets: string[]; memberId?: string }): Promise<DatasetAccessResult[]>; // 读用户授权的数据,见 3.4.2
|
|
110
|
+
};
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
interface MemoryEntry {
|
|
@@ -141,38 +144,134 @@ await BuddyServer.start({
|
|
|
141
144
|
|
|
142
145
|
完整示例见 [examples/aunt-tu/](examples/aunt-tu/):`taste_read` / `taste_write` 两个工具用 `memory` 记每个人爱吃什么、不爱吃什么。
|
|
143
146
|
|
|
144
|
-
|
|
147
|
+
`dataAccess.query` 读取用户授权给搭子的数据,用法见 3.4.2。
|
|
148
|
+
|
|
149
|
+
### 3.4 内置工具:运行时注册给模型
|
|
145
150
|
|
|
146
151
|
以下工具由运行时注册到 Agent,排在开发者工具之前,由模型调用。开发者不需要注册,也不能再注册同名工具;系统提示中可按名称引用。
|
|
147
152
|
|
|
148
153
|
| 工具 | 何时注册 | 做什么 |
|
|
149
154
|
|---|---|---|
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
155
|
+
| `read_resource` | 工程目录下有 `resources/`,且其中有 `.md` | 按资料清单里的相对路径读一篇资料 |
|
|
156
|
+
| `data_access_query` | 搭子声明过至少一个 Dataset | 按需读取当前会话用户授权的数据;单次最多 8 个 Dataset,响应上限 512 KiB |
|
|
157
|
+
| `widget_create` / `widget_write` / `widget_read` / `widget_delete` / `widget_send` | 搭子在平台上登记了小挂件类型 | 建小挂件、写 / 读 / 删记录、把小挂件发进聊天 |
|
|
158
|
+
|
|
159
|
+
#### 3.4.1 资料
|
|
152
160
|
|
|
153
|
-
|
|
161
|
+
资料放在工程目录下的 `resources/` 里,是一篇篇 `.md` 文件。运行时自动让模型按需读取,开发者不需要写代码。
|
|
154
162
|
|
|
155
|
-
|
|
163
|
+
- 读哪些文件:进程启动时读一次 `resources/` 下全部 `.md`,包括子目录;跳过以 `.` 开头的文件与目录,以及 `node_modules`、`venv`、`.venv`、`__pycache__`;其他扩展名的文件忽略。资料改动后需重启进程。
|
|
164
|
+
- 模型看到什么:系统提示末尾追加一份资料清单,列出每篇资料相对 `resources/` 的路径;模型调用 `read_resource` 并传入清单中的路径,读到该篇全文。
|
|
165
|
+
- 没有资料时:`resources/` 不存在或其中没有 `.md`,不注册 `read_resource`,也不追加清单。
|
|
156
166
|
|
|
157
167
|
```
|
|
158
|
-
my-buddy/
|
|
159
|
-
├─
|
|
168
|
+
my-buddy/ 工程目录
|
|
169
|
+
├─ package.json
|
|
170
|
+
├─ resources/ 资料目录
|
|
160
171
|
│ └─ research/
|
|
161
172
|
│ └─ 01-writings.md 清单中写作 research/01-writings.md
|
|
162
|
-
└─ src/main.ts
|
|
173
|
+
└─ src/main.ts 入口脚本
|
|
163
174
|
```
|
|
164
175
|
|
|
165
176
|
完整示例见 [examples/stacy-sims/](examples/stacy-sims/)。
|
|
166
177
|
|
|
167
|
-
####
|
|
178
|
+
#### 3.4.2 授权数据
|
|
179
|
+
|
|
180
|
+
经用户同意,搭子可以读取用户授权数据。数据按 Dataset 分项,每项内容与字段固定,用户逐项授权。开发者要做的是声明需要哪些 Dataset;查询工具由运行时注册给模型,开发者的工具里也能直接查。
|
|
181
|
+
|
|
182
|
+
**声明需要哪些数据**
|
|
183
|
+
|
|
184
|
+
通过平台 CLI 接口 `PUT /cli/buddies/:id/data-requirements` 提交完整清单,每次提交覆盖上一次:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"datasets": [
|
|
189
|
+
{ "id": "health.sleep", "purpose": "根据你最近的睡眠调整作息建议" }
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
- `id`:从下表选。
|
|
195
|
+
- `purpose`:写给用户看的用途,1~200 字。用户在 App 里看到这句话,再决定是否同意。
|
|
196
|
+
- 改了某项的 `purpose`,用户之前的同意失效,要重新同意;从清单里删掉的数据,搭子立即读不到。
|
|
197
|
+
- 声明或改动之后,重启搭子进程,模型才能看到新的清单。
|
|
198
|
+
|
|
199
|
+
目前支持的 Dataset:
|
|
200
|
+
|
|
201
|
+
| Dataset | 内容 | `data.items` 每条的字段 |
|
|
202
|
+
|---|---|---|
|
|
203
|
+
| `health.sleep` | 睡眠,每天一条 | `date`、`totalSleepMinutes`、`sleepStartLocal`、`sleepEndLocal`、`awakeMinutes`、`coreSleepMinutes`、`deepSleepMinutes`、`remSleepMinutes`、`unspecifiedSleepMinutes` |
|
|
204
|
+
| `health.workouts` | 运动记录,每次一条 | `id`、`date`、`startAt`、`type`、`durationMinutes`、`calories`、`sourceApp` |
|
|
205
|
+
| `health.distance` | 距离与配速,对应一次运动 | `workoutId`、`date`、`startAt`、`distanceKm`、`paceSecondsPerKm` |
|
|
206
|
+
| `health.heartRate` | 心率,对应一段睡眠或一次运动 | `context`(`sleep` / `workout`)、`referenceId`、`date`、`startAt`、`beatsPerMinute` |
|
|
207
|
+
| `health.hrv` | 心率变异性 | `date`、`milliseconds` |
|
|
208
|
+
| `health.respiratoryRate` | 呼吸频率 | `date`、`breathsPerMinute` |
|
|
209
|
+
| `health.oxygenSaturation` | 血氧 | `date`、`percent` |
|
|
210
|
+
| `health.environmentalAudioExposure` | 环境音量 | `date`、`decibels` |
|
|
211
|
+
|
|
212
|
+
部分字段可能缺失,取值前先判断。
|
|
213
|
+
|
|
214
|
+
**让模型去查**
|
|
215
|
+
|
|
216
|
+
声明过至少一项数据,模型就有了 `data_access_query` 工具,工具说明里列着开发者声明的数据与用途。开发者可以在系统提示里写明什么时候查,例如「聊到作息时,先用 data_access_query 查 health.sleep」。
|
|
217
|
+
|
|
218
|
+
**在自己的工具里查**
|
|
219
|
+
|
|
220
|
+
调用 `conversation.dataAccess.query`:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const [sleep] = await conversation.dataAccess.query({ datasets: ["health.sleep"] });
|
|
224
|
+
if (sleep.status === "available") {
|
|
225
|
+
// sleep.data.items 是每天一条的睡眠记录
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
- `datasets`:一次最多 8 个。
|
|
230
|
+
- `memberId`:私聊不传;群聊必须传,即群消息前缀 `[名字 #m_…]` 里的 `m_…`,查的是这位成员的数据。传错时直接抛出异常。
|
|
231
|
+
|
|
232
|
+
**查询结果**
|
|
233
|
+
|
|
234
|
+
每个 Dataset 各有一个状态,一个读不到不影响其他。只有 `available` 带 `data`:
|
|
235
|
+
|
|
236
|
+
| 状态 | 意思 |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `available` | 读到了 |
|
|
239
|
+
| `notDeclared` | 搭子没有声明这项数据 |
|
|
240
|
+
| `notGranted` | 用户没有同意,或改过用途后用户还没重新同意 |
|
|
241
|
+
| `disabledInGroup` | 这位成员在这个群里关掉了这项数据 |
|
|
242
|
+
| `unavailable` | 平台上还没有这位用户的这项数据,或数据已过期 |
|
|
243
|
+
|
|
244
|
+
**数据只在这一轮回复里可见**
|
|
245
|
+
|
|
246
|
+
一轮回复里只要查过授权数据,这一轮结束后,聊天记录和会话历史里这一轮的工具参数、工具结果与 thinking,都会换成「查了哪些数据、各是什么状态」,给用户看的回复照常保留。开发者自己写进 `memory` 或小挂件的内容不会被替换,不要把查到的数据写进去。
|
|
247
|
+
|
|
248
|
+
#### 3.4.3 小挂件
|
|
168
249
|
|
|
169
250
|
开发者通过平台 CLI 接口给搭子登记小挂件类型:`PUT /cli/buddies/:id/widget-types/:typeId/schema` 交 schema,每个模块写一句 `description` 给模型读,每条记录的形状是一份 JSON Schema;`PUT /cli/buddies/:id/widget-types/:typeId/page` 交展示页面,单个 HTML 文件。
|
|
170
251
|
|
|
171
|
-
运行时在第一场会话建立时拉一次 `GET /internal/v1/widget-types`,按拉到的类型注册五个 `widget_*`
|
|
252
|
+
运行时在第一场会话建立时拉一次 `GET /internal/v1/widget-types`,按拉到的类型注册五个 `widget_*` 工具,工具说明里附上各类型的模块与字段;一个类型都没登记时不注册。这场会话里已有哪些小挂件,由平台写进消息流的会话上下文告诉模型。
|
|
172
253
|
|
|
173
254
|
用法见 [examples/aunt-tu/](examples/aunt-tu/)。
|
|
174
255
|
|
|
175
|
-
##
|
|
256
|
+
## 4. 会话历史:MLBMessage → AgentMessage → LLMMessage
|
|
257
|
+
|
|
258
|
+
开发者不需要保存会话历史,也不需要把聊天里的消息换成模型消息,这些由运行时完成。每场会话的消息都保存在平台上,搭子进程重启后历史照样在。从平台上的 `MLBMessage` 到模型收到的 `LLMMessage`:
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
MLBMessage[] → AgentMessage[] → transformContext() → AgentMessage[] → convertToLlm() → LLMMessage[] → LLM
|
|
262
|
+
▲ (1) │ ▲ (2) (3) │
|
|
263
|
+
└─────(5)──────┘ └──────────────────────────────────────(4)───────────────────────────────────────┘
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
1. 平台上的 `MLBMessage` 换成 pi 的 `AgentMessage`,追加进会话历史。一条消息只换一次:会话起来时换一遍平台上已有的全部消息,之后来一条换一条。什么消息换成什么,见 4.1。
|
|
267
|
+
2. `transformContext()`:开发者可选。入参是完整的会话历史,返回值只用于这一次请求,不改动历史。
|
|
268
|
+
3. `convertToLlm()`:运行时实现,开发者不能替换,做什么见 4.3。换出来的 `LLMMessage`(即 pi-ai 的 `Message`)连同 `systemPrompt` 与 `tools` 发给模型。
|
|
269
|
+
4. 模型的回复,以及它调用工具得到的结果,直接追加进会话历史,不经过 (1)。
|
|
270
|
+
5. 经 (4) 追加进历史的消息,运行时再换成 `MLBMessage` 写回平台;经 (1) 从平台来的不会写回。用户在聊天里看到的回复就是这一步写上去的。用过授权数据的那一轮,写回前先脱敏,见 3.4.2。搭子重启后,这些消息经 (1) 取回。
|
|
271
|
+
|
|
272
|
+
(1) 在消息到来时发生;(2)、(3) 在每次请求模型前都完整跑一遍,一轮回复里模型可能请求好几次,比如调完工具接着说,每次都从当时完整的会话历史重新算;(4)、(5) 在模型每说完一段、每跑完一步工具时发生。
|
|
273
|
+
|
|
274
|
+
## 5. 环境变量
|
|
176
275
|
|
|
177
276
|
| 变量 | 说明 |
|
|
178
277
|
|---|---|
|
|
@@ -183,7 +282,8 @@ my-buddy/
|
|
|
183
282
|
|
|
184
283
|
搭子的档案(名称、头像、简介)由平台保存:注册时通过 `POST /cli/buddies` 提交,修改通过 `PUT /cli/buddies/:id/meta`。搭子进程不监听端口、不接收入站请求。从非回环地址连接网关时,平台将其识别为 `<id>-dev` 分身,会话与正式身份隔离。
|
|
185
284
|
|
|
186
|
-
## 开发
|
|
285
|
+
## 6. 开发
|
|
187
286
|
|
|
188
287
|
- `npm run dev`:以 `node --watch` 启动,文件变更后自动重启。停止时需终止整个进程树(`pkill -f "node --watch .* src/main.ts"`),仅终止子进程会被父进程重新拉起。
|
|
288
|
+
- 会话消息拉取遇到临时网络错误时会主动指数退避重试(1 秒起步、最高 30 秒);新的 SSE 通知会取消等待并立即重拉。
|
|
189
289
|
- 运行时仓库:`npm test`、`npm run typecheck`、`npm run build`。
|
|
@@ -2,8 +2,9 @@ import { Agent } from "@earendil-works/pi-agent-core";
|
|
|
2
2
|
import type { AgentEvent, StreamFn } from "@earendil-works/pi-agent-core";
|
|
3
3
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
4
4
|
import type { MLBClient, WidgetType } from "../mlbClient.ts";
|
|
5
|
+
import { DataAccessUsageTracker } from "../tools/dataAccess.ts";
|
|
5
6
|
import type { Resource } from "../tools/resource.ts";
|
|
6
|
-
import type { BuddyFactory, BuddyLogger } from "../types.ts";
|
|
7
|
+
import type { BuddyFactory, BuddyLogger, DataRequirement } from "../types.ts";
|
|
7
8
|
export interface AgentDeps {
|
|
8
9
|
key: string;
|
|
9
10
|
buddyId: string;
|
|
@@ -15,13 +16,16 @@ export interface AgentDeps {
|
|
|
15
16
|
widgetTypes: () => Promise<WidgetType[]>;
|
|
16
17
|
/** 搭子目录下 resources/ 里的资料;空数组就不装 read_resource、不接清单 */
|
|
17
18
|
resources: Resource[];
|
|
19
|
+
dataRequirements: () => Promise<DataRequirement[]>;
|
|
18
20
|
factory: BuddyFactory;
|
|
19
21
|
log: BuddyLogger;
|
|
20
|
-
/** 每次模型调用前现取平台 context 段;空就不插 */
|
|
21
|
-
contextOf: () => string | undefined;
|
|
22
22
|
/** Agent 事件的去处。pi 会等它返回,所以只能同步做事 */
|
|
23
23
|
onEvent: (agent: Agent, event: AgentEvent) => void;
|
|
24
24
|
}
|
|
25
25
|
/** 跑开发者工厂拿配置,叠上运行时预置,建 Agent。开发者的工具名跟运行时的工具(小挂件、read_resource)重名或互相重名 → throw。 */
|
|
26
|
-
export
|
|
26
|
+
export interface CreatedAgent {
|
|
27
|
+
agent: Agent;
|
|
28
|
+
dataAccessUsage: DataAccessUsageTracker;
|
|
29
|
+
}
|
|
30
|
+
export declare function createAgent(deps: AgentDeps): Promise<CreatedAgent>;
|
|
27
31
|
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/conversation/agent.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAa,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAErF,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/conversation/agent.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAa,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAErF,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGxD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAkB,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAA8B,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1G,MAAM,WAAW,SAAS;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACzC,sDAAsD;IACtD,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,gBAAgB,EAAE,MAAM,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACnD,OAAO,EAAE,YAAY,CAAC;IACtB,GAAG,EAAE,WAAW,CAAC;IACjB,oCAAoC;IACpC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACnD;AAED,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,sBAAsB,CAAC;CACxC;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CA2GxE"}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
// 一场会话的 Agent 怎么建:运行时先把该填的填好,开发者的配置叠上去。
|
|
2
|
-
// 管:拼好交给开发者工厂的 Conversation(会话键、日志、绑好会话键的 memory
|
|
3
|
-
//
|
|
2
|
+
// 管:拼好交给开发者工厂的 Conversation(会话键、日志、绑好会话键的 memory / DataAccess),跑工厂拿配置;
|
|
3
|
+
// 运行时工具(DataAccess、小挂件、有资料时的 read_resource)排在开发者工具前面并查重名;有资料时把资料清单接在 systemPrompt 末尾;
|
|
4
4
|
// 开发者显式设的 thinkingLevel 这个模型不支持时打一条 warn,写明支持哪几档、实际会怎么发;
|
|
5
|
-
// 钩子叠加——开发者的 transformContext
|
|
6
|
-
//
|
|
5
|
+
// 钩子叠加——开发者的 transformContext 包 try/catch 抛了用原历史;开发者的 beforeToolCall 包 try/catch 抛了按放行;其余直通;
|
|
6
|
+
// 模型调用日志只记规模,不打印消息、Tool 结果和请求体,避免用户对话与授权数据进入日志。
|
|
7
7
|
// 不管:Agent 建好之后的事(回合、事件分发在 index.ts)。
|
|
8
8
|
import { Agent } from "@earendil-works/pi-agent-core";
|
|
9
9
|
import { clampThinkingLevel, getSupportedThinkingLevels } from "@earendil-works/pi-ai";
|
|
10
|
-
import {
|
|
10
|
+
import { agentMessagesToLLMMessages } from "./agentMessageLLMMessageConverter.js";
|
|
11
11
|
import { errorText } from "../log.js";
|
|
12
|
+
import { dataAccessTool, DataAccessUsageTracker } from "../tools/dataAccess.js";
|
|
12
13
|
import { readResourceTool, resourceCatalog } from "../tools/resource.js";
|
|
13
14
|
import { widgetTools } from "../tools/widgets.js";
|
|
14
|
-
/** 跑开发者工厂拿配置,叠上运行时预置,建 Agent。开发者的工具名跟运行时的工具(小挂件、read_resource)重名或互相重名 → throw。 */
|
|
15
15
|
export async function createAgent(deps) {
|
|
16
|
+
const dataAccessUsage = new DataAccessUsageTracker();
|
|
16
17
|
const conversation = {
|
|
17
18
|
key: deps.key,
|
|
18
19
|
log: deps.log,
|
|
@@ -21,14 +22,19 @@ export async function createAgent(deps) {
|
|
|
21
22
|
write: (key, text) => deps.client.memoryWrite(deps.key, key, text),
|
|
22
23
|
delete: (key) => deps.client.memoryDelete(deps.key, key),
|
|
23
24
|
},
|
|
25
|
+
dataAccess: {
|
|
26
|
+
query: ({ datasets, memberId }) => dataAccessUsage.query(deps.client, deps.key, datasets, memberId),
|
|
27
|
+
},
|
|
24
28
|
};
|
|
25
29
|
const options = await deps.factory(conversation);
|
|
26
|
-
const types = await deps.widgetTypes();
|
|
30
|
+
const [types, requirements] = await Promise.all([deps.widgetTypes(), deps.dataRequirements()]);
|
|
31
|
+
const dataTools = requirements.length === 0 ? [] : [dataAccessTool(deps.client, deps.key, dataAccessUsage, requirements)];
|
|
27
32
|
const tools = [
|
|
33
|
+
...dataTools,
|
|
28
34
|
...widgetTools(deps.client, deps.key, types),
|
|
29
35
|
...(deps.resources.length > 0 ? [readResourceTool(deps.resources)] : []),
|
|
30
36
|
...(options.initialState.tools ?? []),
|
|
31
|
-
];
|
|
37
|
+
].map((tool) => dataAccessUsage.track(tool));
|
|
32
38
|
const seen = new Set();
|
|
33
39
|
for (const tool of tools) {
|
|
34
40
|
if (seen.has(tool.name))
|
|
@@ -52,6 +58,7 @@ export async function createAgent(deps) {
|
|
|
52
58
|
const catalog = resourceCatalog(deps.resources);
|
|
53
59
|
const devTransform = options.transformContext;
|
|
54
60
|
const devBefore = options.beforeToolCall;
|
|
61
|
+
const devAfter = options.afterToolCall;
|
|
55
62
|
const agent = new Agent({
|
|
56
63
|
streamFn: deps.streamFn,
|
|
57
64
|
getApiKey: () => deps.token,
|
|
@@ -65,38 +72,36 @@ export async function createAgent(deps) {
|
|
|
65
72
|
},
|
|
66
73
|
steeringMode: "all",
|
|
67
74
|
followUpMode: "all",
|
|
68
|
-
// 下面三个钩子按 pi
|
|
69
|
-
//
|
|
75
|
+
// 下面三个钩子按 pi 每次请求模型时的调用顺序排;只记录规模,不记录正文或请求体。
|
|
76
|
+
// 平台的场合交代是历史里的记录,不在这里插;这里只跑开发者的裁剪
|
|
70
77
|
transformContext: async (messages, signal) => {
|
|
71
|
-
log.info("transformContext 入参", { convoKey: key, messages });
|
|
78
|
+
log.info("transformContext 入参", { convoKey: key, messageCount: messages.length });
|
|
79
|
+
if (devTransform === undefined)
|
|
80
|
+
return messages;
|
|
72
81
|
let base = messages;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
base = messages;
|
|
80
|
-
}
|
|
81
|
-
log.info("开发者 transformContext 出参", { convoKey: key, messages: base });
|
|
82
|
+
try {
|
|
83
|
+
base = await devTransform(messages, signal);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
log.warn("开发者的 transformContext 抛错,用原历史", { convoKey: key, error: errorText(e) });
|
|
87
|
+
base = messages;
|
|
82
88
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return injected;
|
|
89
|
+
log.info("开发者 transformContext 出参", { convoKey: key, messageCount: base.length });
|
|
90
|
+
return base;
|
|
86
91
|
},
|
|
87
92
|
convertToLlm: (messages) => {
|
|
88
|
-
const llmMessages =
|
|
89
|
-
log.info("convertToLlm 出参", { convoKey: key,
|
|
93
|
+
const llmMessages = agentMessagesToLLMMessages(messages);
|
|
94
|
+
log.info("convertToLlm 出参", { convoKey: key, messageCount: llmMessages.length });
|
|
90
95
|
return llmMessages;
|
|
91
96
|
},
|
|
92
97
|
// 只打日志、返回 undefined:返回别的值 pi-ai 会拿它顶替请求体发出去
|
|
93
|
-
onPayload: (
|
|
94
|
-
log.info("
|
|
98
|
+
onPayload: () => {
|
|
99
|
+
log.info("模型请求已构建", { convoKey: key });
|
|
95
100
|
return undefined;
|
|
96
101
|
},
|
|
97
102
|
beforeToolCall: devBefore === undefined
|
|
98
103
|
? undefined
|
|
99
|
-
: async (context, signal) => {
|
|
104
|
+
: async (context, signal) => dataAccessUsage.runForTool(context.toolCall.id, async () => {
|
|
100
105
|
try {
|
|
101
106
|
return await devBefore(context, signal);
|
|
102
107
|
}
|
|
@@ -104,14 +109,16 @@ export async function createAgent(deps) {
|
|
|
104
109
|
log.warn("开发者的 beforeToolCall 抛错,按放行", { convoKey: key, tool: context.toolCall.name, error: errorText(e) });
|
|
105
110
|
return undefined;
|
|
106
111
|
}
|
|
107
|
-
},
|
|
108
|
-
afterToolCall:
|
|
112
|
+
}),
|
|
113
|
+
afterToolCall: devAfter === undefined
|
|
114
|
+
? undefined
|
|
115
|
+
: (context, signal) => dataAccessUsage.runForTool(context.toolCall.id, () => devAfter(context, signal)),
|
|
109
116
|
shouldStopAfterTurn: options.shouldStopAfterTurn,
|
|
110
117
|
prepareNextTurnWithContext: options.prepareNextTurnWithContext,
|
|
111
118
|
thinkingBudgets: options.thinkingBudgets,
|
|
112
119
|
toolExecution: options.toolExecution,
|
|
113
120
|
});
|
|
114
121
|
agent.subscribe((event) => deps.onEvent(agent, event));
|
|
115
|
-
return agent;
|
|
122
|
+
return { agent, dataAccessUsage };
|
|
116
123
|
}
|
|
117
124
|
//# sourceMappingURL=agent.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/conversation/agent.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/conversation/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import type { Message } from "@earendil-works/pi-ai";
|
|
3
|
+
/**
|
|
4
|
+
* note 变 user;相邻两条 user 合并成一条(正文中间隔一个换行);user / assistant / toolResult 原样。
|
|
5
|
+
* 返回的是新数组,合并出来的也是新对象,不改传进来的消息。
|
|
6
|
+
*/
|
|
7
|
+
export declare const agentMessagesToLLMMessages: (messages: AgentMessage[]) => Message[];
|
|
8
|
+
//# sourceMappingURL=agentMessageLLMMessageConverter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentMessageLLMMessageConverter.d.ts","sourceRoot":"","sources":["../../src/conversation/agentMessageLLMMessageConverter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAgB,OAAO,EAA4B,MAAM,uBAAuB,CAAC;AAE7F;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,UAAU,YAAY,EAAE,KAAG,OAAO,EAa5E,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// AgentMessage → LLMMessage 的换算:交给 pi 的 convertToLlm,每次请求模型前把 Agent 历史(经开发者 transformContext 之后的)换成模型收的消息(pi-ai 的 Message)。
|
|
2
|
+
// MLBMessage 与 AgentMessage 之间的换算不在这里,在 mlbMessageAgentMessageConverter.ts。
|
|
3
|
+
/**
|
|
4
|
+
* note 变 user;相邻两条 user 合并成一条(正文中间隔一个换行);user / assistant / toolResult 原样。
|
|
5
|
+
* 返回的是新数组,合并出来的也是新对象,不改传进来的消息。
|
|
6
|
+
*/
|
|
7
|
+
export const agentMessagesToLLMMessages = (messages) => {
|
|
8
|
+
const out = [];
|
|
9
|
+
for (const m of messages) {
|
|
10
|
+
const next = agentMessageToLLMMessage(m);
|
|
11
|
+
if (next === undefined)
|
|
12
|
+
continue;
|
|
13
|
+
const prev = out[out.length - 1];
|
|
14
|
+
if (next.role === "user" && prev !== undefined && prev.role === "user") {
|
|
15
|
+
out[out.length - 1] = mergeUsers(prev, next);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
out.push(next);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
};
|
|
23
|
+
/** 一条 AgentMessage 到模型那边是什么:note 变 user;pi harness 自己并进来的那几种 role(bashExecution / custom / …)这个运行时不产生,照 pi 默认 convertToLlm 的做法不给模型 */
|
|
24
|
+
function agentMessageToLLMMessage(m) {
|
|
25
|
+
switch (m.role) {
|
|
26
|
+
case "note":
|
|
27
|
+
return { role: "user", content: [{ type: "text", text: m.text }], timestamp: m.timestamp };
|
|
28
|
+
case "user":
|
|
29
|
+
case "assistant":
|
|
30
|
+
case "toolResult":
|
|
31
|
+
return m;
|
|
32
|
+
default:
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function mergeUsers(a, b) {
|
|
37
|
+
const blocks = [...userBlocks(a), ...userBlocks(b)];
|
|
38
|
+
const text = blocks
|
|
39
|
+
.filter((block) => block.type === "text")
|
|
40
|
+
.map((block) => block.text)
|
|
41
|
+
.join("\n");
|
|
42
|
+
const images = blocks.filter((block) => block.type === "image");
|
|
43
|
+
return { role: "user", content: [{ type: "text", text }, ...images], timestamp: a.timestamp };
|
|
44
|
+
}
|
|
45
|
+
function userBlocks(m) {
|
|
46
|
+
return typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=agentMessageLLMMessageConverter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentMessageLLMMessageConverter.js","sourceRoot":"","sources":["../../src/conversation/agentMessageLLMMessageConverter.ts"],"names":[],"mappings":"AAAA,4HAA4H;AAC5H,4EAA4E;AAK5E;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,QAAwB,EAAa,EAAE;IACjF,MAAM,GAAG,GAAc,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,wBAAwB,CAAC,CAAC,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,SAAS;YAAE,SAAS;QACjC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACxE,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACP,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC,CAAC;AAEF,sIAAsI;AACtI,SAAS,wBAAwB,CAAC,CAAe;IAChD,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,MAAM;YACV,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC;QAC5F,KAAK,MAAM,CAAC;QACZ,KAAK,WAAW,CAAC;QACjB,KAAK,YAAY;YAChB,OAAO,CAAC,CAAC;QACV;YACC,OAAO,SAAS,CAAC;IACnB,CAAC;AACF,CAAC;AAED,SAAS,UAAU,CAAC,CAAc,EAAE,CAAc;IACjD,MAAM,MAAM,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM;SACjB,MAAM,CAAC,CAAC,KAAK,EAAwB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC;SAC9D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;SAC1B,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAyB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IACvF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,GAAG,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC;AAC/F,CAAC;AAED,SAAS,UAAU,CAAC,CAAc;IACjC,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AACxF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type { AssistantMessage, Message, ToolResultMessage } from "@earendil-works/pi-ai";
|
|
3
|
-
import type { NoteMessage, OutgoingMessage
|
|
3
|
+
import type { MLBMessage, NoteMessage, OutgoingMessage } from "../types.ts";
|
|
4
4
|
/** 重建 assistant 消息时抄的模型身份(model.ts 的 modelIdentity 给) */
|
|
5
5
|
export interface ModelIdentity {
|
|
6
6
|
api: string;
|
|
@@ -9,15 +9,16 @@ export interface ModelIdentity {
|
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* 把一批平台记录换成 pi 的历史。跳过的:interrupted 的半截话、question / widget、空正文又没工具调用的搭子记录。
|
|
12
|
-
* 对方的 message 变 user(群里带成员前缀)、system 变 user(带「群里发生了一件事」)、messagesCard 拍平成 user
|
|
12
|
+
* 对方的 message 变 user(群里带成员前缀)、system 变 user(带「群里发生了一件事」)、messagesCard 拍平成 user、
|
|
13
|
+
* 平台的场合交代 context 原样变 user(开头自带「平台交代给你的情况」那句用法,不套前缀);
|
|
13
14
|
* 搭子的 message / checkin 变 assistant,tool 变 assistant + 每个调用一条 toolResult,note 变 note。
|
|
14
15
|
*/
|
|
15
|
-
export declare function toAgentMessages(records:
|
|
16
|
+
export declare function toAgentMessages(records: MLBMessage[], identity: ModelIdentity): AgentMessage[];
|
|
16
17
|
/**
|
|
17
18
|
* 不带工具调用的 assistant 消息写成 message 记录。
|
|
18
19
|
* 正常收尾的照写(带 thinking);error / aborted 收尾但已经说了半截的写成 interrupted;其余不写。
|
|
19
20
|
*/
|
|
20
|
-
export declare function outboundFromAssistant(m: AssistantMessage): OutgoingMessage | null;
|
|
21
|
+
export declare function outboundFromAssistant(m: AssistantMessage, omitThinking?: boolean): OutgoingMessage | null;
|
|
21
22
|
/**
|
|
22
23
|
* 带工具调用的 assistant 消息连同它的结果写成一条 tool 记录;每个调用的 summary 取工具的 label,没有 label 用名字。
|
|
23
24
|
* 没有工具调用的返回 null(那种走 outboundFromAssistant)。
|
|
@@ -25,7 +26,12 @@ export declare function outboundFromAssistant(m: AssistantMessage): OutgoingMess
|
|
|
25
26
|
export declare function outboundFromTurn(m: AssistantMessage, toolResults: ToolResultMessage[], tools: {
|
|
26
27
|
name: string;
|
|
27
28
|
label: string;
|
|
28
|
-
}[]): OutgoingMessage | null;
|
|
29
|
+
}[], dataAccessDetailsOf?: (toolCallId: string) => unknown, sensitiveRun?: boolean): OutgoingMessage | null;
|
|
30
|
+
/**
|
|
31
|
+
* Agent run 完成后,把内存 transcript 里的 DataAccess 原始结果换成状态摘要。
|
|
32
|
+
* run 内不能提前替换:模型在 Tool 后续一轮还需要读取真实数据。
|
|
33
|
+
*/
|
|
34
|
+
export declare function redactSensitiveRun(messages: AgentMessage[], runMessages: AgentMessage[], dataAccessDetailsOf?: (toolCallId: string) => unknown): AgentMessage[];
|
|
29
35
|
/** note 消息写成 note 记录 */
|
|
30
36
|
export declare function outboundFromNote(n: NoteMessage): OutgoingMessage;
|
|
31
37
|
/** assistant 消息里所有 thinking 块的推理原文拼起来;一个字都没有返回 undefined */
|
|
@@ -37,10 +43,4 @@ export declare function textOf(m: AssistantMessage): string;
|
|
|
37
43
|
* 返回的是新数组,合并出来的也是新对象,不改传进来的消息。
|
|
38
44
|
*/
|
|
39
45
|
export declare const convertToLlm: (messages: AgentMessage[]) => Message[];
|
|
40
|
-
/**
|
|
41
|
-
* 把平台随拉取下发的 context 段插进历史:找到末尾那段连续的 user(note 也算,它到模型那边就是 user),插在这段前面,
|
|
42
|
-
* 后面的 convertToLlm 会把它跟这段合并;末尾是 assistant / toolResult 时,往前找最后一段 user 插在它前面。
|
|
43
|
-
* context 为空原样返回;否则返回新数组,不改传进来的。
|
|
44
|
-
*/
|
|
45
|
-
export declare function injectContext(messages: AgentMessage[], context: string | undefined): AgentMessage[];
|
|
46
46
|
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/conversation/convert.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EACX,gBAAgB,EAEhB,OAAO,EAIP,iBAAiB,EAGjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAgB,WAAW,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/conversation/convert.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EACX,gBAAgB,EAEhB,OAAO,EAIP,iBAAiB,EAGjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAgB,UAAU,EAAe,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGvG,yDAAyD;AACzD,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACd;AA6BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,aAAa,GAAG,YAAY,EAAE,CAmC9F;AAgFD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,gBAAgB,EAAE,YAAY,UAAQ,GAAG,eAAe,GAAG,IAAI,CAQvG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC/B,CAAC,EAAE,gBAAgB,EACnB,WAAW,EAAE,iBAAiB,EAAE,EAChC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,EACxC,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,EACrD,YAAY,UAAQ,GAClB,eAAe,GAAG,IAAI,CAqBxB;AASD;;;GAGG;AAEH,wBAAgB,kBAAkB,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,WAAW,EAAE,YAAY,EAAE,EAC3B,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,GACnD,YAAY,EAAE,CAqBhB;AAED,wBAAwB;AACxB,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,GAAG,eAAe,CAEhE;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAMlE;AAED,mCAAmC;AACnC,wBAAgB,MAAM,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAKlD;AAYD;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,UAAU,YAAY,EAAE,KAAG,OAAO,EAa9D,CAAC"}
|