@springbrand/agent-runtime 0.1.3-alpha.0 → 0.1.3-alpha.2
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/package.json +1 -1
- package/src/db/schema.ts +10 -1
- package/src/db/submission.repo.ts +34 -1
- package/src/index.ts +9 -11
- package/src/kernel/bindings.ts +27 -6
- package/src/kernel/extensions.ts +1 -1
- package/src/kernel/profile.ts +3 -4
- package/src/kernel/recoverable-chat-agent.ts +82 -4
- package/src/kernel/state.ts +4 -0
- package/src/kernel/submission-lifecycle.ts +3 -2
- package/src/layers/orchestration/temporary-agent/runner.ts +0 -65
- package/src/lib/prompt.ts +1 -1
- package/src/pi/assembly/context.ts +1 -3
- package/src/pi/assembly/snapshot.ts +17 -9
- package/src/pi/runtime-adapter/assembly.ts +25 -86
- package/src/pi/runtime-adapter/execution.ts +107 -12
- package/src/pi/runtime-adapter/index.ts +8 -3
- package/src/pi/runtime-adapter/models.ts +221 -29
- package/src/pi/runtime-adapter/transcript.ts +61 -3
- package/src/pi/tool/ai-adapter.ts +58 -1
- package/src/pi/tool/base.ts +112 -2
- package/src/pi/tool/compiler.ts +5 -32
- package/src/pi/tool/core-host.ts +28 -30
- package/src/pi/tool/core.ts +25 -122
- package/src/pi/tool/mcp.ts +2 -2
- package/src/pi/tool/schedule.ts +46 -2
- package/src/pi/tool/skill.ts +112 -420
- package/src/pi/tool/web-fetch.ts +282 -0
- package/src/pi/tool/web-search/api.ts +34 -18
- package/src/pi/tool/workspace-sandbox.ts +92 -258
- package/src/plugins.ts +358 -531
- package/src/runtime.ts +195 -44
package/src/plugins.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { SkillSource } from "agents/skills";
|
|
2
2
|
import type {
|
|
3
|
+
RuntimeCodeExecutionPort,
|
|
3
4
|
RuntimeMemoryPort,
|
|
4
5
|
RuntimePlatformPort,
|
|
5
6
|
RuntimeProviderPort,
|
|
6
7
|
RuntimeSandboxPort,
|
|
7
8
|
RuntimeSchedulePort,
|
|
9
|
+
RuntimeSkillSourceBinding,
|
|
8
10
|
RuntimeSubagentPort,
|
|
9
11
|
RuntimeTurnEventsPort,
|
|
10
12
|
RuntimeBindings,
|
|
@@ -27,15 +29,30 @@ import {
|
|
|
27
29
|
} from "./lib/execution-level";
|
|
28
30
|
import {
|
|
29
31
|
createPiRuntimeAssembly,
|
|
32
|
+
type PiToolSurface,
|
|
30
33
|
type PiRuntimeAssembly,
|
|
31
34
|
} from "./pi/assembly/snapshot";
|
|
32
35
|
import type { PiToolCandidate } from "./pi/tool/compiler";
|
|
33
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
basePiToolCandidates,
|
|
38
|
+
memoryPiToolCandidate,
|
|
39
|
+
} from "./pi/tool/base";
|
|
40
|
+
import {
|
|
41
|
+
browserQuickActionPiToolCandidates,
|
|
42
|
+
codeExecutionPiToolCandidate,
|
|
43
|
+
} from "./pi/tool/core";
|
|
44
|
+
import {
|
|
45
|
+
sandboxPiToolCandidates,
|
|
46
|
+
workspacePiToolCandidates,
|
|
47
|
+
} from "./pi/tool/workspace-sandbox";
|
|
48
|
+
import { schedulePiToolCandidates } from "./pi/tool/schedule";
|
|
49
|
+
import { skillPiToolCandidates } from "./pi/tool/skill";
|
|
50
|
+
import { subagentPiToolCandidates } from "./pi/tool/subagent";
|
|
34
51
|
import { createWebSearch } from "./pi/tool/web-search";
|
|
35
52
|
import { resolvePiModel } from "./pi/runtime-adapter/models";
|
|
36
53
|
|
|
37
54
|
/**
|
|
38
|
-
* 本文件实现 Plugin
|
|
55
|
+
* 本文件实现 Plugin 的准备、声明合并、校验和原子候选装配。
|
|
39
56
|
*
|
|
40
57
|
* @remarks
|
|
41
58
|
* 核心术语见包入口 `index.ts`,这里不重复定义。
|
|
@@ -70,332 +87,152 @@ export type PluginKind =
|
|
|
70
87
|
export type { RuntimeDegradation } from "./kernel/degradation";
|
|
71
88
|
|
|
72
89
|
/**
|
|
73
|
-
*
|
|
90
|
+
* 提供 Runtime 核心运行参数。
|
|
74
91
|
*
|
|
75
92
|
* @remarks
|
|
76
|
-
* `
|
|
93
|
+
* `profile` Plugin 在准备结果中返回它。
|
|
77
94
|
*
|
|
78
|
-
*
|
|
95
|
+
* 这里只放业务可配置字段,冻结和最终结构由 Runtime 负责。
|
|
79
96
|
*/
|
|
80
|
-
export interface
|
|
81
|
-
readonly
|
|
82
|
-
readonly
|
|
97
|
+
export interface RuntimeProfileContribution {
|
|
98
|
+
readonly model: string;
|
|
99
|
+
readonly thinking: ThinkingEffort;
|
|
100
|
+
readonly systemPrompt?: string;
|
|
101
|
+
readonly executionLevel: ExecutionLevel;
|
|
83
102
|
}
|
|
84
103
|
|
|
85
104
|
/**
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* @remarks
|
|
89
|
-
* 应用把它放进 `AgentConfig.plugins`。
|
|
90
|
-
*
|
|
91
|
-
* Runtime 只调用 `prepare`,不会接触 Plugin 捕获的业务依赖。
|
|
105
|
+
* 描述一个已准备 Skill。
|
|
92
106
|
*/
|
|
93
|
-
export interface
|
|
94
|
-
readonly
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
* @remarks
|
|
99
|
-
* Runtime 在生成候选结果时调用,应用只需把 Plugin 放进 `AgentConfig`。
|
|
100
|
-
*
|
|
101
|
-
* 读取与贡献分开,是为了并行读取外部数据后再按稳定顺序合并。
|
|
102
|
-
*/
|
|
103
|
-
prepare(): Promise<PreparedPlugin>;
|
|
107
|
+
export interface RuntimeSkillContribution {
|
|
108
|
+
readonly name: string;
|
|
109
|
+
readonly description: string;
|
|
110
|
+
readonly source: SkillSource;
|
|
111
|
+
readonly script?: Partial<RuntimeSkillScriptPolicy>;
|
|
104
112
|
}
|
|
105
113
|
|
|
106
114
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* @remarks
|
|
110
|
-
* Runtime 按固定 kind 顺序调用 `contribute`。
|
|
111
|
-
*
|
|
112
|
-
* 准备和贡献分开,才能并行读取数据又保持确定的合并顺序。
|
|
115
|
+
* 描述一个已准备 Extension。
|
|
113
116
|
*/
|
|
114
|
-
export interface
|
|
115
|
-
readonly
|
|
116
|
-
readonly
|
|
117
|
-
/**
|
|
118
|
-
* 把已读取的值写进 Runtime 提供的受限候选上下文。
|
|
119
|
-
*
|
|
120
|
-
* @remarks
|
|
121
|
-
* Runtime 在全部 loader 完成后,按 `PluginKind` 固定顺序调用。
|
|
122
|
-
*
|
|
123
|
-
* 这一阶段只能使用受限上下文,不能直接安装 Snapshot。
|
|
124
|
-
*/
|
|
125
|
-
contribute(
|
|
126
|
-
ctx: RuntimeContributionContext,
|
|
127
|
-
): void | Promise<void>;
|
|
117
|
+
export interface RuntimeExtensionContribution {
|
|
118
|
+
readonly name: string;
|
|
119
|
+
readonly extension: RuntimeExtensionConfig;
|
|
128
120
|
}
|
|
129
121
|
|
|
130
122
|
/**
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* @remarks
|
|
134
|
-
* 应用把该对象传给 `definePlugin`。
|
|
123
|
+
* 描述 Agent 对最终 Tool Surface 的可见性约束。
|
|
135
124
|
*
|
|
136
|
-
*
|
|
125
|
+
* Host 只提供策略;Runtime 在唯一 Tool Surface seam 中对所有
|
|
126
|
+
* Port 和 Resource 生成的候选项统一应用。
|
|
137
127
|
*/
|
|
138
|
-
export interface
|
|
139
|
-
readonly
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
*
|
|
143
|
-
* @remarks
|
|
144
|
-
* `definePlugin` 包装出的 `prepare` 会在 Runtime 装配开始时调用它。
|
|
145
|
-
*
|
|
146
|
-
* 它只返回数据和降级信息,不应直接修改正在运行的 Runtime。
|
|
147
|
-
*/
|
|
148
|
-
loader(): Promise<PluginLoadResult<T>>;
|
|
149
|
-
/**
|
|
150
|
-
* 在贡献阶段把已读取的数据交给 Runtime。
|
|
151
|
-
*
|
|
152
|
-
* @remarks
|
|
153
|
-
* Runtime 准备完所有 Plugin 后,通过 `PreparedPlugin.contribute` 调用它。
|
|
154
|
-
*
|
|
155
|
-
* 它必须通过 `RuntimeContributionContext` 写入候选结果,以便统一检查重复与跨能力约束。
|
|
156
|
-
*/
|
|
157
|
-
contribute(
|
|
158
|
-
loaded: T,
|
|
159
|
-
ctx: RuntimeContributionContext,
|
|
160
|
-
): void | Promise<void>;
|
|
128
|
+
export interface RuntimeToolSurfacePolicy {
|
|
129
|
+
readonly denyPolicy?: RuntimeDenyPolicy;
|
|
130
|
+
readonly allowsTool?: (name: string) => boolean;
|
|
131
|
+
readonly allowsExtension?: (extension: RuntimeExtensionConfig) => boolean;
|
|
161
132
|
}
|
|
162
133
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
readonly
|
|
134
|
+
interface PluginResultByKind {
|
|
135
|
+
readonly scope: {
|
|
136
|
+
readonly commitGuards: readonly (() => Promise<void>)[];
|
|
137
|
+
};
|
|
138
|
+
readonly profile: { readonly profile: RuntimeProfileContribution };
|
|
139
|
+
readonly provider: { readonly provider: RuntimeProviderPort };
|
|
140
|
+
readonly platform: {
|
|
141
|
+
readonly platform: RuntimePlatformPort;
|
|
142
|
+
};
|
|
143
|
+
readonly workspace: {
|
|
144
|
+
readonly workspace?: WorkspacePort;
|
|
145
|
+
readonly codeExecution?: RuntimeCodeExecutionPort;
|
|
146
|
+
};
|
|
147
|
+
readonly sandbox: {
|
|
148
|
+
readonly sandbox?: RuntimeSandboxPort;
|
|
149
|
+
};
|
|
150
|
+
readonly memory: {
|
|
151
|
+
readonly memoryProfile: RuntimeMemoryProfile;
|
|
152
|
+
readonly memoryPort?: RuntimeMemoryPort;
|
|
153
|
+
};
|
|
154
|
+
readonly tool: {
|
|
155
|
+
readonly hostTools: readonly PiToolCandidate[];
|
|
156
|
+
readonly policy?: RuntimeToolSurfacePolicy;
|
|
157
|
+
};
|
|
158
|
+
readonly skill: {
|
|
159
|
+
readonly skills: readonly RuntimeSkillContribution[];
|
|
160
|
+
};
|
|
161
|
+
readonly connector: {
|
|
162
|
+
readonly connectors: readonly RuntimeMcpServer[];
|
|
163
|
+
};
|
|
164
|
+
readonly extension: {
|
|
165
|
+
readonly extensions: readonly RuntimeExtensionContribution[];
|
|
166
|
+
};
|
|
167
|
+
readonly schedule: {
|
|
168
|
+
readonly schedule: RuntimeSchedulePort;
|
|
169
|
+
};
|
|
170
|
+
readonly subagent: {
|
|
171
|
+
readonly enabledSubagents: readonly string[];
|
|
172
|
+
readonly subagents?: RuntimeSubagentPort;
|
|
173
|
+
};
|
|
174
|
+
readonly "turn-events": {
|
|
175
|
+
readonly turnEvents: RuntimeTurnEventsPort;
|
|
176
|
+
};
|
|
173
177
|
}
|
|
174
178
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
readonly
|
|
179
|
+
export type PluginPreparation<K extends PluginKind> = Readonly<
|
|
180
|
+
PluginResultByKind[K] & {
|
|
181
|
+
readonly degradations: readonly RuntimeDegradation[];
|
|
182
|
+
}
|
|
183
|
+
>;
|
|
184
|
+
|
|
185
|
+
export type PreparedPlugin<K extends PluginKind = PluginKind> =
|
|
186
|
+
K extends PluginKind
|
|
187
|
+
? Readonly<PluginPreparation<K> & { readonly kind: K }>
|
|
188
|
+
: never;
|
|
189
|
+
|
|
190
|
+
interface AgentPluginContract<K extends PluginKind> {
|
|
191
|
+
readonly kind: K;
|
|
192
|
+
prepare(): Promise<PreparedPlugin<K>>;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export type AgentPlugin<K extends PluginKind = PluginKind> =
|
|
196
|
+
K extends PluginKind ? AgentPluginContract<K> : never;
|
|
197
|
+
|
|
198
|
+
export interface AgentPluginSpec<K extends PluginKind> {
|
|
199
|
+
readonly kind: K;
|
|
200
|
+
prepare(): Promise<PluginPreparation<K>>;
|
|
188
201
|
}
|
|
189
202
|
|
|
190
203
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* @remarks
|
|
194
|
-
* Plugin 的 `contribute` 回调使用这些方法。
|
|
195
|
-
*
|
|
196
|
-
* Runtime 只暴露绑定和增量添加操作,避免 Plugin 取得 Builder 的可变引用。
|
|
204
|
+
* 汇总一次 Runtime 装配要使用的全部 Plugin。
|
|
197
205
|
*/
|
|
198
|
-
export interface
|
|
199
|
-
|
|
200
|
-
* 写入唯一的模型、提示词、审批和权限配置。
|
|
201
|
-
*
|
|
202
|
-
* @remarks
|
|
203
|
-
* profile Plugin 在贡献阶段调用一次。
|
|
204
|
-
*
|
|
205
|
-
* Runtime 拒绝第二份配置,避免候选结果同时有两个运行参数来源。
|
|
206
|
-
*/
|
|
207
|
-
configureProfile(profile: RuntimeProfileContribution): void;
|
|
208
|
-
/**
|
|
209
|
-
* 写入部署提供的模型端点与凭据。
|
|
210
|
-
*
|
|
211
|
-
* @remarks
|
|
212
|
-
* provider Plugin 在贡献阶段调用一次。
|
|
213
|
-
*
|
|
214
|
-
* Runtime 保留单一 Provider 选择,并在生成候选结果时检查默认模型、端点和凭据。
|
|
215
|
-
*/
|
|
216
|
-
bindProvider(provider: RuntimeProviderPort): void;
|
|
217
|
-
/**
|
|
218
|
-
* 写入唯一的 Cloudflare 平台端口。
|
|
219
|
-
*
|
|
220
|
-
* @remarks
|
|
221
|
-
* platform Plugin 在贡献阶段调用一次。
|
|
222
|
-
*
|
|
223
|
-
* Loader 和出口函数作为一个整体绑定,不允许从多个平台配置静默拼接。
|
|
224
|
-
*/
|
|
225
|
-
bindPlatform(platform: RuntimePlatformPort): void;
|
|
226
|
-
/**
|
|
227
|
-
* 写入可选的工作区端口。
|
|
228
|
-
*
|
|
229
|
-
* @remarks
|
|
230
|
-
* workspace Plugin 在工作区可用时调用一次。
|
|
231
|
-
*
|
|
232
|
-
* Runtime 只允许一个当前工作区;未绑定时依赖它的能力必须降级或在校验时失败。
|
|
233
|
-
*/
|
|
234
|
-
bindWorkspace(workspace: WorkspacePort): void;
|
|
235
|
-
/**
|
|
236
|
-
* 写入可选的 Linux Sandbox 执行端口。
|
|
237
|
-
*
|
|
238
|
-
* @remarks
|
|
239
|
-
* sandbox Plugin 在部署和 Agent 配置都启用该能力时调用。
|
|
240
|
-
*
|
|
241
|
-
* Sandbox 必须和持久工作区成对出现,这个跨能力约束在提交前统一校验。
|
|
242
|
-
*/
|
|
243
|
-
bindSandbox(
|
|
244
|
-
sandbox: RuntimeSandboxPort,
|
|
245
|
-
): void;
|
|
246
|
-
/**
|
|
247
|
-
* 写入内存参数,并在启用时提供内存读写端口。
|
|
248
|
-
*
|
|
249
|
-
* @remarks
|
|
250
|
-
* memory Plugin 在贡献阶段调用一次,即使功能关闭也要传入 profile。
|
|
251
|
-
*
|
|
252
|
-
* 独立记录“已配置”状态,才能区分未贡献与明确关闭。
|
|
253
|
-
*/
|
|
254
|
-
configureMemory(
|
|
255
|
-
profile: RuntimeMemoryProfile,
|
|
256
|
-
port?: RuntimeMemoryPort,
|
|
257
|
-
): void;
|
|
258
|
-
/**
|
|
259
|
-
* 添加一个已经过装配期授权、并保留审批元数据的 Pi Tool 候选。
|
|
260
|
-
*
|
|
261
|
-
* @remarks
|
|
262
|
-
* tool Plugin 为当前 Agent 真正可见的 Tool 逐个调用。
|
|
263
|
-
*
|
|
264
|
-
* Runtime 在装配期拒绝空名和重名,避免 Pi 开始 Turn 后才发现能力冲突。
|
|
265
|
-
*/
|
|
266
|
-
addPiTool(candidate: PiToolCandidate): void;
|
|
267
|
-
/**
|
|
268
|
-
* 写入唯一的 Turn 期拒绝清单。
|
|
269
|
-
*
|
|
270
|
-
* @remarks
|
|
271
|
-
* tool Plugin 在完成实际可见能力挑选后调用一次。
|
|
272
|
-
*
|
|
273
|
-
* 能力的有无在注入前已经决定,这里只保留 Turn 期仍需执行的拒绝规则。
|
|
274
|
-
*/
|
|
275
|
-
configureDenyPolicy(
|
|
276
|
-
policy?: RuntimeDenyPolicy,
|
|
277
|
-
): void;
|
|
278
|
-
/**
|
|
279
|
-
* 添加一个已授权 Skill 的持久化 catalog、内容来源及脚本权限。
|
|
280
|
-
*
|
|
281
|
-
* @remarks
|
|
282
|
-
* skill Plugin 为已解析的外部 Skill 逐个调用。
|
|
283
|
-
*
|
|
284
|
-
* catalog、来源与权限一起登记,同时和其他 Skill 来源共享同一名称空间。
|
|
285
|
-
*/
|
|
286
|
-
addSkillSource(
|
|
287
|
-
name: string,
|
|
288
|
-
description: string,
|
|
289
|
-
source: SkillSource,
|
|
290
|
-
script?: Partial<RuntimeSkillScriptPolicy>,
|
|
291
|
-
): void;
|
|
292
|
-
/**
|
|
293
|
-
* 按名称添加一个 MCP Connector。
|
|
294
|
-
*
|
|
295
|
-
* @remarks
|
|
296
|
-
* connector Plugin 为当前 Agent 已授权的连接逐个调用。
|
|
297
|
-
*
|
|
298
|
-
* Runtime 在装配期统一规范化名称和 URL,并拒绝空值或重名。
|
|
299
|
-
*/
|
|
300
|
-
addConnector(server: RuntimeMcpServer): void;
|
|
301
|
-
/**
|
|
302
|
-
* 按名称添加一个已验证的 Runtime Extension。
|
|
303
|
-
*
|
|
304
|
-
* @remarks
|
|
305
|
-
* extension Plugin 为当前部署的扩展逐个调用。
|
|
306
|
-
*
|
|
307
|
-
* 登记名必须和 manifest 名一致,否则配置选择可能指向错误的执行对象。
|
|
308
|
-
*/
|
|
309
|
-
addExtension(name: string, extension: RuntimeExtensionConfig): void;
|
|
310
|
-
/**
|
|
311
|
-
* 写入唯一的定时任务端口。
|
|
312
|
-
*
|
|
313
|
-
* @remarks
|
|
314
|
-
* schedule Plugin 在贡献阶段调用一次。
|
|
315
|
-
*
|
|
316
|
-
* 本端口只描述回到当前 Session 的调用边界;Cloudflare 的实际唤醒和回调路由 Host 与 Agents SDK 管理。
|
|
317
|
-
*/
|
|
318
|
-
bindSchedule(schedule: RuntimeSchedulePort): void;
|
|
319
|
-
/**
|
|
320
|
-
* 标记一个 Subagent 类型在本次 Runtime 中启用。
|
|
321
|
-
*
|
|
322
|
-
* @remarks
|
|
323
|
-
* subagent Plugin 通过部署检查后为每种可用类型调用。
|
|
324
|
-
*
|
|
325
|
-
* Runtime 只把已启用名称交给 Pi,并在提交前确认执行端口存在。
|
|
326
|
-
*/
|
|
327
|
-
enableSubagent(name: string): void;
|
|
328
|
-
/**
|
|
329
|
-
* 写入唯一的 Subagent 执行端口。
|
|
330
|
-
*
|
|
331
|
-
* @remarks
|
|
332
|
-
* subagent Plugin 在至少启用一种类型时调用一次。
|
|
333
|
-
*
|
|
334
|
-
* 类型选择和实际执行能力分开登记,缺少端口时由统一校验拒绝候选结果。
|
|
335
|
-
*/
|
|
336
|
-
bindSubagents(subagents: RuntimeSubagentPort): void;
|
|
337
|
-
/**
|
|
338
|
-
* 写入唯一的 Turn 完成事件端口。
|
|
339
|
-
*
|
|
340
|
-
* @remarks
|
|
341
|
-
* turn-events Plugin 在贡献阶段调用一次。
|
|
342
|
-
*
|
|
343
|
-
* 单一端口保证应用投影只有一个顺序来源,避免同一完成事件被重复写入。
|
|
344
|
-
*/
|
|
345
|
-
bindTurnEvents(turnEvents: RuntimeTurnEventsPort): void;
|
|
346
|
-
/**
|
|
347
|
-
* 添加一个最终提交前必须通过的异步检查。
|
|
348
|
-
*
|
|
349
|
-
* @remarks
|
|
350
|
-
* 会在 loader 执行期间过期的 scope Plugin 在贡献时添加它。
|
|
351
|
-
*
|
|
352
|
-
* Runtime 延迟到全部候选内容就绪后再运行 guard,防止旧业务条件被提交。
|
|
353
|
-
*/
|
|
354
|
-
addCommitGuard(guard: () => Promise<void>): void;
|
|
355
|
-
/**
|
|
356
|
-
* 记录一项不阻止启动的能力降级。
|
|
357
|
-
*
|
|
358
|
-
* @remarks
|
|
359
|
-
* Runtime 在贡献每个 PreparedPlugin 前,把它的降级信息逐项写入。
|
|
360
|
-
*
|
|
361
|
-
* 记录时会复制并冻结顶层对象,避免已提交诊断被 Plugin 后续改写。
|
|
362
|
-
*/
|
|
363
|
-
reportDegradation(degradation: RuntimeDegradation): void;
|
|
206
|
+
export interface AgentConfig {
|
|
207
|
+
readonly plugins: readonly AgentPlugin[];
|
|
364
208
|
}
|
|
365
209
|
|
|
366
210
|
/**
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* @remarks
|
|
370
|
-
* 应用在创建 `AgentConfig` 时调用它,不需要手写 `prepare`。
|
|
211
|
+
* 定义一个只准备声明式结果的 Runtime Plugin。
|
|
371
212
|
*
|
|
372
|
-
*
|
|
213
|
+
* Runtime 内部负责排序、合并、冲突检查和提交。
|
|
373
214
|
*/
|
|
374
|
-
export function definePlugin<
|
|
375
|
-
spec: AgentPluginSpec<
|
|
376
|
-
): AgentPlugin {
|
|
215
|
+
export function definePlugin<K extends PluginKind>(
|
|
216
|
+
spec: AgentPluginSpec<K>,
|
|
217
|
+
): AgentPlugin<K> {
|
|
377
218
|
return Object.freeze({
|
|
378
219
|
kind: spec.kind,
|
|
379
220
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
// 原因:此处只准备数据,不贡献能力,才能安全地与其他 loader 并行。
|
|
383
|
-
async prepare(): Promise<PreparedPlugin> {
|
|
384
|
-
const loaded = await spec.loader();
|
|
221
|
+
async prepare(): Promise<PreparedPlugin<K>> {
|
|
222
|
+
const prepared = await spec.prepare();
|
|
385
223
|
const degradations = Object.freeze(
|
|
386
|
-
|
|
224
|
+
prepared.degradations.map((degradation) =>
|
|
387
225
|
Object.freeze({ ...degradation }),
|
|
388
226
|
),
|
|
389
227
|
);
|
|
390
228
|
|
|
391
229
|
return Object.freeze({
|
|
230
|
+
...prepared,
|
|
392
231
|
kind: spec.kind,
|
|
393
232
|
degradations,
|
|
394
|
-
|
|
395
|
-
spec.contribute(loaded.value, ctx),
|
|
396
|
-
});
|
|
233
|
+
}) as PreparedPlugin<K>;
|
|
397
234
|
},
|
|
398
|
-
})
|
|
235
|
+
}) as AgentPlugin<K>;
|
|
399
236
|
}
|
|
400
237
|
|
|
401
238
|
// #endregion
|
|
@@ -451,7 +288,6 @@ const DISABLED_MEMORY: RuntimeMemoryProfile = Object.freeze({
|
|
|
451
288
|
enabled: false,
|
|
452
289
|
memoryTokens: 2_000,
|
|
453
290
|
preferencesTokens: 500,
|
|
454
|
-
compactAfterTokens: 100_000,
|
|
455
291
|
});
|
|
456
292
|
|
|
457
293
|
// 作用:把外部名称整理成非空字符串。
|
|
@@ -479,22 +315,140 @@ function assertMemoryProfile(profile: RuntimeMemoryProfile): void {
|
|
|
479
315
|
}
|
|
480
316
|
}
|
|
481
317
|
|
|
318
|
+
interface ToolSurfaceInput {
|
|
319
|
+
readonly platform: RuntimePlatformPort;
|
|
320
|
+
readonly workspace?: WorkspacePort;
|
|
321
|
+
readonly memory?: {
|
|
322
|
+
readonly port: RuntimeMemoryPort;
|
|
323
|
+
readonly profile: RuntimeMemoryProfile;
|
|
324
|
+
};
|
|
325
|
+
readonly codeExecution?: RuntimeCodeExecutionPort;
|
|
326
|
+
readonly sandbox?: RuntimeSandboxPort;
|
|
327
|
+
readonly hostTools: readonly PiToolCandidate[];
|
|
328
|
+
readonly skills: readonly RuntimeSkillSourceBinding[];
|
|
329
|
+
readonly schedule?: RuntimeSchedulePort;
|
|
330
|
+
readonly subagents?: RuntimeSubagentPort;
|
|
331
|
+
readonly enabledSubagents: readonly string[];
|
|
332
|
+
readonly webSearch: Parameters<typeof basePiToolCandidates>[0];
|
|
333
|
+
readonly extensions: readonly RuntimeExtensionConfig[];
|
|
334
|
+
readonly policy?: RuntimeToolSurfacePolicy;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
interface ToolSurface {
|
|
338
|
+
readonly surface: PiToolSurface;
|
|
339
|
+
readonly extensions: readonly RuntimeExtensionConfig[];
|
|
340
|
+
readonly degradations: readonly RuntimeDegradation[];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 唯一 Tool Surface seam:只读取已授权 Port、Resource 和 Agent policy,
|
|
344
|
+
// 统一生成可见 Tool,并在一处做名称、执行档位与冲突校验。
|
|
345
|
+
async function createToolSurface(
|
|
346
|
+
input: ToolSurfaceInput,
|
|
347
|
+
): Promise<ToolSurface> {
|
|
348
|
+
const deny = new Set(input.policy?.denyPolicy?.deny ?? []);
|
|
349
|
+
const allowsTool = input.policy?.allowsTool;
|
|
350
|
+
const allowsExtension = input.policy?.allowsExtension;
|
|
351
|
+
const visible = (candidate: PiToolCandidate) =>
|
|
352
|
+
candidate.authorized &&
|
|
353
|
+
!deny.has(candidate.tool.name) &&
|
|
354
|
+
allowsTool?.(candidate.tool.name) !== false;
|
|
355
|
+
const browserCandidates = input.platform.browser
|
|
356
|
+
? browserQuickActionPiToolCandidates(input.platform.browser)
|
|
357
|
+
: [];
|
|
358
|
+
const workspaceCandidates = input.workspace
|
|
359
|
+
? workspacePiToolCandidates(input.workspace)
|
|
360
|
+
: [];
|
|
361
|
+
const executionCandidates = input.workspace && input.codeExecution
|
|
362
|
+
? [codeExecutionPiToolCandidate(input.codeExecution)]
|
|
363
|
+
: [];
|
|
364
|
+
const sandboxCandidates = input.sandbox
|
|
365
|
+
? sandboxPiToolCandidates(input.sandbox)
|
|
366
|
+
: [];
|
|
367
|
+
const subagentCandidates = subagentPiToolCandidates(
|
|
368
|
+
input.subagents,
|
|
369
|
+
input.enabledSubagents,
|
|
370
|
+
);
|
|
371
|
+
const scheduleCandidates = input.schedule
|
|
372
|
+
? schedulePiToolCandidates(input.schedule)
|
|
373
|
+
: [];
|
|
374
|
+
const baseCandidates = basePiToolCandidates(input.webSearch);
|
|
375
|
+
const memoryCandidates = input.memory
|
|
376
|
+
? [memoryPiToolCandidate(input.memory.port, input.memory.profile)]
|
|
377
|
+
: [];
|
|
378
|
+
const scriptCandidates = [
|
|
379
|
+
...browserCandidates,
|
|
380
|
+
...workspaceCandidates,
|
|
381
|
+
...executionCandidates,
|
|
382
|
+
...sandboxCandidates,
|
|
383
|
+
...input.hostTools,
|
|
384
|
+
...scheduleCandidates,
|
|
385
|
+
...subagentCandidates,
|
|
386
|
+
...baseCandidates,
|
|
387
|
+
...memoryCandidates,
|
|
388
|
+
].filter(visible);
|
|
389
|
+
const staticCandidates = [
|
|
390
|
+
...browserCandidates,
|
|
391
|
+
...workspaceCandidates,
|
|
392
|
+
...executionCandidates,
|
|
393
|
+
...sandboxCandidates,
|
|
394
|
+
...input.hostTools,
|
|
395
|
+
...(await skillPiToolCandidates(input.skills, {
|
|
396
|
+
loader: input.platform.loader,
|
|
397
|
+
...(input.workspace ? { workspace: input.workspace } : {}),
|
|
398
|
+
tools: scriptCandidates,
|
|
399
|
+
})),
|
|
400
|
+
...scheduleCandidates,
|
|
401
|
+
...subagentCandidates,
|
|
402
|
+
...baseCandidates,
|
|
403
|
+
...memoryCandidates,
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
surface: Object.freeze({
|
|
408
|
+
finalize(authorizedCandidates: readonly PiToolCandidate[]) {
|
|
409
|
+
const tools = new Map<string, PiToolCandidate>();
|
|
410
|
+
|
|
411
|
+
for (const candidate of [
|
|
412
|
+
...staticCandidates,
|
|
413
|
+
...authorizedCandidates,
|
|
414
|
+
]) {
|
|
415
|
+
const name = requiredName(candidate.tool.name, "Pi Tool");
|
|
416
|
+
if (!visible(candidate)) continue;
|
|
417
|
+
if (!EXECUTION_LEVELS.includes(candidate.requiredExecutionLevel)) {
|
|
418
|
+
throw new Error(`Pi Tool ${name} execution level is invalid`);
|
|
419
|
+
}
|
|
420
|
+
if (tools.has(name)) {
|
|
421
|
+
throw new Error(`Duplicate Runtime Pi Tool: ${name}`);
|
|
422
|
+
}
|
|
423
|
+
tools.set(name, Object.freeze({ ...candidate }));
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return Object.freeze([...tools.values()]);
|
|
427
|
+
},
|
|
428
|
+
}),
|
|
429
|
+
extensions: input.extensions.filter(
|
|
430
|
+
(extension) => allowsExtension?.(extension) !== false,
|
|
431
|
+
),
|
|
432
|
+
degradations: [],
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
482
436
|
// #endregion
|
|
483
437
|
|
|
484
|
-
// #region RuntimeBuilder
|
|
438
|
+
// #region RuntimeBuilder 合并
|
|
485
439
|
|
|
486
|
-
class RuntimeBuilder
|
|
440
|
+
class RuntimeBuilder {
|
|
487
441
|
private profile?: RuntimeProfileContribution;
|
|
488
442
|
private provider?: RuntimeProviderPort;
|
|
489
443
|
private platform?: RuntimePlatformPort;
|
|
490
444
|
private workspace?: WorkspacePort;
|
|
445
|
+
private codeExecution?: RuntimeCodeExecutionPort;
|
|
491
446
|
private sandbox?: RuntimeSandboxPort;
|
|
447
|
+
private schedule?: RuntimeSchedulePort;
|
|
492
448
|
private memoryProfile: RuntimeMemoryProfile = DISABLED_MEMORY;
|
|
493
449
|
private memory?: RuntimeMemoryPort;
|
|
494
|
-
private
|
|
495
|
-
private
|
|
496
|
-
private denyPolicyConfigured = false;
|
|
497
|
-
private readonly piTools = new Map<string, PiToolCandidate>();
|
|
450
|
+
private readonly hostTools: PiToolCandidate[] = [];
|
|
451
|
+
private toolPolicy?: RuntimeToolSurfacePolicy;
|
|
498
452
|
private readonly skillSources = new Map<
|
|
499
453
|
string,
|
|
500
454
|
{
|
|
@@ -504,156 +458,88 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
504
458
|
script: RuntimeSkillScriptPolicy;
|
|
505
459
|
}
|
|
506
460
|
>();
|
|
507
|
-
private readonly skillDefinitions = new Set<string>();
|
|
508
461
|
private readonly connectors = new Map<string, RuntimeMcpServer>();
|
|
509
462
|
private readonly extensions = new Map<string, RuntimeExtensionConfig>();
|
|
510
|
-
private schedule?: RuntimeSchedulePort;
|
|
511
463
|
private readonly enabledSubagents = new Set<string>();
|
|
512
464
|
private subagents?: RuntimeSubagentPort;
|
|
513
465
|
private turnEvents?: RuntimeTurnEventsPort;
|
|
514
466
|
private readonly commitGuards: Array<() => Promise<void>> = [];
|
|
515
467
|
private readonly degradations: RuntimeDegradation[] = [];
|
|
516
468
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
this.
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
this.
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
// 调用:workspace Plugin 在成功加载工作区后调用。
|
|
579
|
-
// 原因:工作区只有一个当前目录语义,重复绑定会产生不确定行为。
|
|
580
|
-
bindWorkspace(workspace: WorkspacePort): void {
|
|
581
|
-
if (this.workspace) {
|
|
582
|
-
throw new Error("Runtime workspace was contributed more than once");
|
|
583
|
-
}
|
|
584
|
-
this.workspace = workspace;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// 作用:记录本次候选唯一的 Linux Sandbox 执行端口。
|
|
588
|
-
// 调用:sandbox Plugin 在部署与 Agent 双开关都通过后调用。
|
|
589
|
-
// 原因:一个 Chat 只能指向一个由 Host 选定的 Sandbox,重复绑定必须失败。
|
|
590
|
-
bindSandbox(
|
|
591
|
-
sandbox: RuntimeSandboxPort,
|
|
592
|
-
): void {
|
|
593
|
-
if (this.sandbox) {
|
|
594
|
-
throw new Error("Runtime Sandbox was contributed more than once");
|
|
595
|
-
}
|
|
596
|
-
this.sandbox = sandbox;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// 作用:记录内存预算和可选读写端口。
|
|
600
|
-
// 调用:memory Plugin 在贡献阶段调用一次。
|
|
601
|
-
// 原因:即使内存关闭也要记录“已经配置”,以便拒绝第二份冲突配置。
|
|
602
|
-
configureMemory(
|
|
603
|
-
profile: RuntimeMemoryProfile,
|
|
604
|
-
port?: RuntimeMemoryPort,
|
|
605
|
-
): void {
|
|
606
|
-
if (this.memoryConfigured) {
|
|
607
|
-
throw new Error("Runtime memory was contributed more than once");
|
|
608
|
-
}
|
|
609
|
-
this.memoryConfigured = true;
|
|
610
|
-
this.memoryProfile = profile;
|
|
611
|
-
this.memory = port;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// 作用:把一个已授权的 Pi Tool 加入候选 Agent 输入。
|
|
615
|
-
// 调用:tool Plugin 在装配期为实际可见的能力逐个调用。
|
|
616
|
-
// 原因:Pi Tool 自带名称,同名能力必须在进入 Agent 前失败。
|
|
617
|
-
addPiTool(candidate: PiToolCandidate): void {
|
|
618
|
-
const name = requiredName(candidate.tool.name, "Pi Tool");
|
|
619
|
-
if (!EXECUTION_LEVELS.includes(candidate.requiredExecutionLevel)) {
|
|
620
|
-
throw new Error(`Pi Tool ${name} execution level is invalid`);
|
|
469
|
+
merge(prepared: PreparedPlugin): void {
|
|
470
|
+
for (const degradation of prepared.degradations) {
|
|
471
|
+
this.reportDegradation(degradation);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
switch (prepared.kind) {
|
|
475
|
+
case "scope":
|
|
476
|
+
this.commitGuards.push(...prepared.commitGuards);
|
|
477
|
+
break;
|
|
478
|
+
case "profile":
|
|
479
|
+
if (!EXECUTION_LEVELS.includes(prepared.profile.executionLevel)) {
|
|
480
|
+
throw new Error("Runtime execution level is invalid");
|
|
481
|
+
}
|
|
482
|
+
this.profile = prepared.profile;
|
|
483
|
+
break;
|
|
484
|
+
case "provider":
|
|
485
|
+
this.provider = prepared.provider;
|
|
486
|
+
break;
|
|
487
|
+
case "platform":
|
|
488
|
+
this.platform = prepared.platform;
|
|
489
|
+
break;
|
|
490
|
+
case "workspace":
|
|
491
|
+
this.workspace = prepared.workspace;
|
|
492
|
+
this.codeExecution = prepared.codeExecution;
|
|
493
|
+
break;
|
|
494
|
+
case "sandbox":
|
|
495
|
+
this.sandbox = prepared.sandbox;
|
|
496
|
+
break;
|
|
497
|
+
case "memory":
|
|
498
|
+
this.memoryProfile = prepared.memoryProfile;
|
|
499
|
+
this.memory = prepared.memoryPort;
|
|
500
|
+
break;
|
|
501
|
+
case "tool":
|
|
502
|
+
this.hostTools.push(...prepared.hostTools);
|
|
503
|
+
this.toolPolicy = prepared.policy;
|
|
504
|
+
break;
|
|
505
|
+
case "skill":
|
|
506
|
+
for (const skill of prepared.skills) this.addSkill(skill);
|
|
507
|
+
break;
|
|
508
|
+
case "connector":
|
|
509
|
+
for (const connector of prepared.connectors) {
|
|
510
|
+
this.addConnector(connector);
|
|
511
|
+
}
|
|
512
|
+
break;
|
|
513
|
+
case "extension":
|
|
514
|
+
for (const { name, extension } of prepared.extensions) {
|
|
515
|
+
this.addExtension(name, extension);
|
|
516
|
+
}
|
|
517
|
+
break;
|
|
518
|
+
case "schedule":
|
|
519
|
+
this.schedule = prepared.schedule;
|
|
520
|
+
break;
|
|
521
|
+
case "subagent":
|
|
522
|
+
for (const name of prepared.enabledSubagents) {
|
|
523
|
+
this.enabledSubagents.add(requiredName(name, "Subagent"));
|
|
524
|
+
}
|
|
525
|
+
this.subagents = prepared.subagents;
|
|
526
|
+
break;
|
|
527
|
+
case "turn-events":
|
|
528
|
+
this.turnEvents = prepared.turnEvents;
|
|
529
|
+
break;
|
|
621
530
|
}
|
|
622
|
-
if (this.piTools.has(name)) {
|
|
623
|
-
throw new Error(`Duplicate Runtime Pi Tool: ${name}`);
|
|
624
|
-
}
|
|
625
|
-
this.piTools.set(name, candidate);
|
|
626
531
|
}
|
|
627
532
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
policy?: RuntimeDenyPolicy,
|
|
633
|
-
): void {
|
|
634
|
-
if (this.denyPolicyConfigured) {
|
|
635
|
-
throw new Error(
|
|
636
|
-
"Runtime deny policy was contributed more than once",
|
|
637
|
-
);
|
|
533
|
+
private addSkill(skill: RuntimeSkillContribution): void {
|
|
534
|
+
const normalized = requiredName(skill.name, "Skill");
|
|
535
|
+
if (this.skillSources.has(normalized)) {
|
|
536
|
+
throw new Error(`Duplicate Runtime Skill: ${normalized}`);
|
|
638
537
|
}
|
|
639
|
-
this.denyPolicyConfigured = true;
|
|
640
|
-
this.denyPolicy = policy;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// 作用:加入一个 Skill 的持久化 catalog、内容来源及其独立脚本权限。
|
|
644
|
-
// 调用:skill Plugin 为已绑定的 Resource 逐个调用。
|
|
645
|
-
// 原因:catalog、来源和权限一起登记,装配无需读取来源且权限不会在 Skill 之间漂移。
|
|
646
|
-
addSkillSource(
|
|
647
|
-
name: string,
|
|
648
|
-
description: string,
|
|
649
|
-
source: SkillSource,
|
|
650
|
-
script: Partial<RuntimeSkillScriptPolicy> = {},
|
|
651
|
-
): void {
|
|
652
|
-
const normalized = this.addSkillDefinition(name);
|
|
653
538
|
const normalizedDescription = requiredName(
|
|
654
|
-
description,
|
|
539
|
+
skill.description,
|
|
655
540
|
`Runtime Skill "${normalized}" description`,
|
|
656
541
|
);
|
|
542
|
+
const script = skill.script ?? {};
|
|
657
543
|
const network = script.network ?? "none";
|
|
658
544
|
if (network !== "none" && network !== "full") {
|
|
659
545
|
throw new Error(
|
|
@@ -680,7 +566,7 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
680
566
|
this.skillSources.set(normalized, Object.freeze({
|
|
681
567
|
name: normalized,
|
|
682
568
|
description: normalizedDescription,
|
|
683
|
-
source,
|
|
569
|
+
source: skill.source,
|
|
684
570
|
script: Object.freeze({
|
|
685
571
|
network,
|
|
686
572
|
workspace,
|
|
@@ -689,10 +575,7 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
689
575
|
}));
|
|
690
576
|
}
|
|
691
577
|
|
|
692
|
-
|
|
693
|
-
// 调用:connector Plugin 为每个已授权连接逐个调用。
|
|
694
|
-
// 原因:名称和 URL 在提交前规范化,避免运行时才发现空地址或重名。
|
|
695
|
-
addConnector(server: RuntimeMcpServer): void {
|
|
578
|
+
private addConnector(server: RuntimeMcpServer): void {
|
|
696
579
|
const name = requiredName(server.name, "Connector");
|
|
697
580
|
if (this.connectors.has(name)) {
|
|
698
581
|
throw new Error(`Duplicate Runtime Connector: ${name}`);
|
|
@@ -706,10 +589,10 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
706
589
|
}));
|
|
707
590
|
}
|
|
708
591
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
592
|
+
private addExtension(
|
|
593
|
+
name: string,
|
|
594
|
+
extension: RuntimeExtensionConfig,
|
|
595
|
+
): void {
|
|
713
596
|
const normalized = requiredName(name, "Extension");
|
|
714
597
|
if (this.extensions.has(normalized)) {
|
|
715
598
|
throw new Error(`Duplicate Runtime Extension: ${normalized}`);
|
|
@@ -722,54 +605,7 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
722
605
|
this.extensions.set(normalized, extension);
|
|
723
606
|
}
|
|
724
607
|
|
|
725
|
-
|
|
726
|
-
// 调用:schedule Plugin 在贡献阶段调用一次。
|
|
727
|
-
// 原因:定时任务必须回到当前会话所有者,不能选择多个路由。
|
|
728
|
-
bindSchedule(schedule: RuntimeSchedulePort): void {
|
|
729
|
-
if (this.schedule) {
|
|
730
|
-
throw new Error("Runtime Schedule was contributed more than once");
|
|
731
|
-
}
|
|
732
|
-
this.schedule = schedule;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// 作用:标记一个 Subagent 类型在本次运行中可用。
|
|
736
|
-
// 调用:subagent Plugin 完成部署检查后逐个调用。
|
|
737
|
-
// 原因:只记录已部署类型,避免模型拿到无法执行的名称。
|
|
738
|
-
enableSubagent(name: string): void {
|
|
739
|
-
this.enabledSubagents.add(requiredName(name, "Subagent"));
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
// 作用:记录 Subagent 的实际执行端口。
|
|
743
|
-
// 调用:subagent Plugin 至少启用一种类型时调用一次。
|
|
744
|
-
// 原因:启用列表与执行能力分开校验,缺端口时在提交前失败。
|
|
745
|
-
bindSubagents(subagents: RuntimeSubagentPort): void {
|
|
746
|
-
if (this.subagents) {
|
|
747
|
-
throw new Error("Runtime Subagents were contributed more than once");
|
|
748
|
-
}
|
|
749
|
-
this.subagents = subagents;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
// 作用:记录 Turn 完成后的应用投影端口。
|
|
753
|
-
// 调用:turn-events Plugin 在贡献阶段调用一次。
|
|
754
|
-
// 原因:完成事件只有一个顺序来源,重复绑定可能重复写业务状态。
|
|
755
|
-
bindTurnEvents(turnEvents: RuntimeTurnEventsPort): void {
|
|
756
|
-
if (this.turnEvents) {
|
|
757
|
-
throw new Error("Runtime Turn Events were contributed more than once");
|
|
758
|
-
}
|
|
759
|
-
this.turnEvents = turnEvents;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
// 作用:登记一个提交前必须再次通过的业务检查。
|
|
763
|
-
// 调用:容易在加载期间过期的 scope Plugin 添加检查时调用。
|
|
764
|
-
// 原因:检查延迟到最终 commit 前,可阻止过期候选覆盖当前 Runtime。
|
|
765
|
-
addCommitGuard(guard: () => Promise<void>): void {
|
|
766
|
-
this.commitGuards.push(guard);
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// 作用:把一项可继续运行的能力缺失加入诊断。
|
|
770
|
-
// 调用:Runtime 汇总每个 PreparedPlugin 的降级信息时调用。
|
|
771
|
-
// 原因:复制并冻结对象,避免 Plugin 在提交后改写诊断。
|
|
772
|
-
reportDegradation(degradation: RuntimeDegradation): void {
|
|
608
|
+
private reportDegradation(degradation: RuntimeDegradation): void {
|
|
773
609
|
this.degradations.push(Object.freeze({ ...degradation }));
|
|
774
610
|
}
|
|
775
611
|
|
|
@@ -777,10 +613,10 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
777
613
|
|
|
778
614
|
// #region RuntimeBuilder 校验与候选生成
|
|
779
615
|
|
|
780
|
-
//
|
|
781
|
-
// 调用:所有 Plugin
|
|
616
|
+
// 作用:校验全部声明,并生成一个不可变候选 Runtime。
|
|
617
|
+
// 调用:所有 Plugin 按固定顺序完成合并后调用一次。
|
|
782
618
|
// 原因:所有交叉约束都在这里通过后才返回候选,旧 Snapshot 不会半更新。
|
|
783
|
-
build(): RuntimeCandidate {
|
|
619
|
+
async build(): Promise<RuntimeCandidate> {
|
|
784
620
|
if (!this.profile) {
|
|
785
621
|
throw new Error("Runtime profile Plugin did not configure a profile");
|
|
786
622
|
}
|
|
@@ -834,7 +670,7 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
834
670
|
model: this.profile.model.trim(),
|
|
835
671
|
thinking: this.profile.thinking,
|
|
836
672
|
systemPrompt: this.profile.systemPrompt,
|
|
837
|
-
denyPolicy: this.denyPolicy,
|
|
673
|
+
denyPolicy: this.toolPolicy?.denyPolicy,
|
|
838
674
|
enabledSubagents: [...this.enabledSubagents],
|
|
839
675
|
mcpServers: [...this.connectors.values()],
|
|
840
676
|
executionLevel: this.profile.executionLevel,
|
|
@@ -864,23 +700,32 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
864
700
|
}
|
|
865
701
|
const resolvedModel = resolvePiModel(provider, profile.model);
|
|
866
702
|
const endpoint = endpoints[0]!;
|
|
867
|
-
const webSearch =
|
|
868
|
-
|
|
869
|
-
:
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
this.
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
})
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
703
|
+
const webSearch = createWebSearch({
|
|
704
|
+
endpoint,
|
|
705
|
+
model: profile.model,
|
|
706
|
+
maxTokens: resolvedModel.maxTokens,
|
|
707
|
+
reasoning: resolvedModel.reasoning,
|
|
708
|
+
});
|
|
709
|
+
const skillSources = [...this.skillSources.values()];
|
|
710
|
+
const toolSurface = await createToolSurface({
|
|
711
|
+
platform: this.platform,
|
|
712
|
+
...(this.workspace ? { workspace: this.workspace } : {}),
|
|
713
|
+
...(this.memoryProfile.enabled && this.memory
|
|
714
|
+
? { memory: { port: this.memory, profile: this.memoryProfile } }
|
|
715
|
+
: {}),
|
|
716
|
+
...(this.codeExecution ? { codeExecution: this.codeExecution } : {}),
|
|
717
|
+
...(this.sandbox ? { sandbox: this.sandbox } : {}),
|
|
718
|
+
hostTools: this.hostTools,
|
|
719
|
+
skills: skillSources,
|
|
720
|
+
...(this.schedule ? { schedule: this.schedule } : {}),
|
|
721
|
+
...(this.subagents ? { subagents: this.subagents } : {}),
|
|
722
|
+
enabledSubagents: [...this.enabledSubagents],
|
|
723
|
+
webSearch,
|
|
724
|
+
extensions: [...this.extensions.values()],
|
|
725
|
+
...(this.toolPolicy ? { policy: this.toolPolicy } : {}),
|
|
726
|
+
});
|
|
727
|
+
for (const degradation of toolSurface.degradations) {
|
|
728
|
+
this.reportDegradation(degradation);
|
|
884
729
|
}
|
|
885
730
|
const bindings: RuntimeBindings = Object.freeze({
|
|
886
731
|
provider,
|
|
@@ -890,9 +735,7 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
890
735
|
? { memory: this.memory }
|
|
891
736
|
: {}),
|
|
892
737
|
skills: Object.freeze({
|
|
893
|
-
sources: Object.freeze(
|
|
894
|
-
...this.skillSources.values(),
|
|
895
|
-
]),
|
|
738
|
+
sources: Object.freeze(skillSources),
|
|
896
739
|
}),
|
|
897
740
|
...(this.turnEvents ? { turnEvents: this.turnEvents } : {}),
|
|
898
741
|
});
|
|
@@ -902,9 +745,9 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
902
745
|
pi: createPiRuntimeAssembly({
|
|
903
746
|
profile,
|
|
904
747
|
provider,
|
|
905
|
-
|
|
748
|
+
toolSurface: toolSurface.surface,
|
|
906
749
|
mcpServers: profile.mcpServers,
|
|
907
|
-
extensions:
|
|
750
|
+
extensions: toolSurface.extensions,
|
|
908
751
|
}),
|
|
909
752
|
degradations: Object.freeze([
|
|
910
753
|
...this.degradations,
|
|
@@ -919,21 +762,10 @@ class RuntimeBuilder implements RuntimeContributionContext {
|
|
|
919
762
|
});
|
|
920
763
|
}
|
|
921
764
|
|
|
922
|
-
// 作用:登记一个 Skill 名称并返回规范化结果。
|
|
923
|
-
// 调用:Host 文档和外部 Skill 来源写入前调用。
|
|
924
|
-
// 原因:所有 Skill 来源共享一个命名空间,重名必须在装配时暴露。
|
|
925
|
-
private addSkillDefinition(name: string): string {
|
|
926
|
-
const normalized = requiredName(name, "Skill");
|
|
927
|
-
if (this.skillDefinitions.has(normalized)) {
|
|
928
|
-
throw new Error(`Duplicate Runtime Skill: ${normalized}`);
|
|
929
|
-
}
|
|
930
|
-
this.skillDefinitions.add(normalized);
|
|
931
|
-
return normalized;
|
|
932
|
-
}
|
|
933
765
|
}
|
|
934
766
|
|
|
935
767
|
// 作用:检查 Plugin kind 合法、唯一,并包含所有必需能力。
|
|
936
|
-
// 调用:任何
|
|
768
|
+
// 调用:任何 prepare 启动前由 `prepareRuntimeCandidate` 调用。
|
|
937
769
|
// 原因:先校验结构可避免为注定失败的配置执行外部读取。
|
|
938
770
|
function validatePluginKinds(
|
|
939
771
|
plugins: readonly AgentPlugin[],
|
|
@@ -968,7 +800,7 @@ function validatePluginKinds(
|
|
|
968
800
|
* @remarks
|
|
969
801
|
* `AgentRuntimeKernel` 在初始化或重载时调用它。
|
|
970
802
|
*
|
|
971
|
-
*
|
|
803
|
+
* prepare 并行执行,声明按固定 kind 顺序合并,任何失败都不会产生 commit。
|
|
972
804
|
*
|
|
973
805
|
* 该函数有意不从包入口导出,提交生命周期只能由 Kernel 控制。
|
|
974
806
|
*
|
|
@@ -994,16 +826,11 @@ export async function prepareRuntimeCandidate(
|
|
|
994
826
|
prepared.map((plugin) => [plugin.kind, plugin]),
|
|
995
827
|
);
|
|
996
828
|
const builder = new RuntimeBuilder();
|
|
997
|
-
const contributionContext =
|
|
998
|
-
builder.contributionContext();
|
|
999
829
|
|
|
1000
830
|
for (const kind of PLUGIN_ORDER) {
|
|
1001
831
|
const plugin = byKind.get(kind);
|
|
1002
832
|
if (!plugin) continue;
|
|
1003
|
-
|
|
1004
|
-
builder.reportDegradation(degradation);
|
|
1005
|
-
}
|
|
1006
|
-
await plugin.contribute(contributionContext);
|
|
833
|
+
builder.merge(plugin);
|
|
1007
834
|
}
|
|
1008
835
|
|
|
1009
836
|
return builder.build();
|
|
@@ -1015,7 +842,7 @@ export async function prepareRuntimeCandidate(
|
|
|
1015
842
|
* @remarks
|
|
1016
843
|
* `AgentRuntimeKernel.initConfig` 在首次加载或显式重载时调用它。
|
|
1017
844
|
*
|
|
1018
|
-
* `commit`
|
|
845
|
+
* `commit` 只在全部准备、合并、校验和 guard 成功后调用一次。
|
|
1019
846
|
*
|
|
1020
847
|
* @internal
|
|
1021
848
|
*/
|