@springbrand/agent-runtime 0.1.3-alpha.3 → 0.1.3-alpha.5
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 +3 -1
- package/src/adapter/cloudflare/index.ts +60 -0
- package/src/adapter/cloudflare/resources/runtime-resources.ts +86 -0
- package/src/adapter/cloudflare/sandbox/adapter.ts +1509 -0
- package/src/adapter/cloudflare/sandbox/id.ts +23 -0
- package/src/adapter/cloudflare/sandbox/policy.ts +15 -0
- package/src/adapter/cloudflare/subagent/definition.ts +574 -0
- package/src/adapter/cloudflare/subagent/runner.ts +175 -0
- package/src/adapter/cloudflare/subagent/tools.ts +256 -0
- package/src/adapter/cloudflare/universal-agent/definition.ts +71 -0
- package/src/adapter/cloudflare/universal-agent/hooks.ts +35 -0
- package/src/adapter/cloudflare/universal-agent/preparation.ts +273 -0
- package/src/adapter/cloudflare/universal-agent/tools.ts +74 -0
- package/src/adapter/cloudflare/workspace/publisher.ts +31 -0
- package/src/adapter/cloudflare/workspace/scoped-workspace.ts +376 -0
- package/src/agent-tool-runtime.ts +152 -0
- package/src/db/agent-tool.repo.ts +27 -0
- package/src/db/index.ts +33 -0
- package/src/db/interaction.repo.ts +185 -0
- package/src/db/schema.ts +15 -0
- package/src/db/submission.repo.ts +29 -0
- package/src/index.ts +53 -21
- package/src/kernel/approval-lifecycle.ts +41 -6
- package/src/kernel/bindings.ts +37 -0
- package/src/kernel/interaction-lifecycle.ts +395 -0
- package/src/kernel/public-contracts.ts +2 -0
- package/src/kernel/recoverable-chat-agent.ts +10 -2
- package/src/kernel/runtime-assembly-view.ts +37 -0
- package/src/kernel/runtime-assembly.ts +41 -0
- package/src/kernel/runtime-config.ts +4 -0
- package/src/kernel/runtime-load.ts +102 -0
- package/src/kernel/state.ts +8 -1
- package/src/kernel/submission-lifecycle.ts +30 -0
- package/src/layers/orchestration/temporary-agent/core.ts +12 -1
- package/src/layers/orchestration/temporary-agent/runner.ts +1 -2
- package/src/pi/message/contract.ts +7 -0
- package/src/pi/message/conversion.ts +9 -1
- package/src/pi/runtime-adapter/assembly.ts +17 -3
- package/src/pi/runtime-adapter/execution.ts +109 -9
- package/src/pi/runtime-adapter/index.ts +15 -5
- package/src/pi/runtime-adapter/recovery.ts +188 -1
- package/src/pi/tool/base.ts +79 -9
- package/src/pi/tool/compiler.ts +34 -0
- package/src/pi/tool/core.ts +13 -0
- package/src/pi/tool/gateway.ts +54 -0
- package/src/pi/tool/index.ts +1 -0
- package/src/pi/tool/mcp.ts +93 -64
- package/src/pi/tool/schedule.ts +11 -0
- package/src/pi/tool/subagent.ts +14 -0
- package/src/pi/tool/workspace-sandbox.ts +15 -0
- package/src/pi/turn/index.ts +20 -0
- package/src/pi/turn/interaction.ts +181 -0
- package/src/pi/turn/tool-recovery.ts +244 -1
- package/src/runtime-agent-context.ts +112 -0
- package/src/runtime-agent.ts +569 -322
- package/src/{plugins.ts → runtime-assembler.ts} +312 -379
- package/src/runtime-definition.ts +173 -0
- package/src/runtime.ts +572 -164
- package/src/tool-registry.ts +143 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SkillSource } from "agents/skills";
|
|
2
2
|
import type {
|
|
3
3
|
RuntimeCodeExecutionPort,
|
|
4
|
+
RuntimeGatewayPort,
|
|
4
5
|
RuntimeMemoryPort,
|
|
5
6
|
RuntimePlatformPort,
|
|
6
7
|
RuntimeProviderPort,
|
|
@@ -32,212 +33,64 @@ import {
|
|
|
32
33
|
type PiToolSurface,
|
|
33
34
|
type PiRuntimeAssembly,
|
|
34
35
|
} from "./pi/assembly/snapshot";
|
|
36
|
+
import type { AgentTool } from "@earendil-works/pi-agent-core";
|
|
35
37
|
import type { PiToolCandidate } from "./pi/tool/compiler";
|
|
38
|
+
import type {
|
|
39
|
+
AssembleRuntimeSnapshotInput,
|
|
40
|
+
RuntimeAgentHooks,
|
|
41
|
+
RuntimeSettings,
|
|
42
|
+
RuntimeExtensionContribution,
|
|
43
|
+
RuntimeProfileContribution,
|
|
44
|
+
RuntimeSkillContribution,
|
|
45
|
+
RuntimeToolSurfacePolicy,
|
|
46
|
+
} from "./runtime-definition";
|
|
47
|
+
import type { ToolRegistry } from "./tool-registry";
|
|
36
48
|
import {
|
|
37
49
|
basePiToolCandidates,
|
|
38
50
|
memoryPiToolCandidate,
|
|
39
51
|
} from "./pi/tool/base";
|
|
40
52
|
import {
|
|
41
53
|
browserQuickActionPiToolCandidates,
|
|
42
|
-
codeExecutionPiToolCandidate,
|
|
43
54
|
} from "./pi/tool/core";
|
|
44
|
-
import {
|
|
45
|
-
sandboxPiToolCandidates,
|
|
46
|
-
workspacePiToolCandidates,
|
|
47
|
-
} from "./pi/tool/workspace-sandbox";
|
|
48
|
-
import { schedulePiToolCandidates } from "./pi/tool/schedule";
|
|
49
55
|
import { skillPiToolCandidates } from "./pi/tool/skill";
|
|
50
|
-
import { subagentPiToolCandidates } from "./pi/tool/subagent";
|
|
51
56
|
import { createWebSearch } from "./pi/tool/web-search";
|
|
52
57
|
import { resolvePiModel } from "./pi/runtime-adapter/models";
|
|
53
58
|
|
|
54
|
-
/**
|
|
55
|
-
* 本文件实现 Plugin 的准备、声明合并、校验和原子候选装配。
|
|
56
|
-
*
|
|
57
|
-
* @remarks
|
|
58
|
-
* 核心术语见包入口 `index.ts`,这里不重复定义。
|
|
59
|
-
*/
|
|
60
|
-
|
|
61
|
-
// #region Plugin 公开契约
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 标明一个 Plugin 负责哪一类能力。
|
|
65
|
-
*
|
|
66
|
-
* @remarks
|
|
67
|
-
* 应用创建 Plugin 时必须选择其中一个值。
|
|
68
|
-
*
|
|
69
|
-
* Runtime 用它拒绝重复能力并确定贡献顺序,所以不要把它当作自由文本。
|
|
70
|
-
*/
|
|
71
|
-
export type PluginKind =
|
|
72
|
-
| "scope"
|
|
73
|
-
| "profile"
|
|
74
|
-
| "provider"
|
|
75
|
-
| "platform"
|
|
76
|
-
| "workspace"
|
|
77
|
-
| "sandbox"
|
|
78
|
-
| "memory"
|
|
79
|
-
| "tool"
|
|
80
|
-
| "skill"
|
|
81
|
-
| "connector"
|
|
82
|
-
| "extension"
|
|
83
|
-
| "schedule"
|
|
84
|
-
| "subagent"
|
|
85
|
-
| "turn-events";
|
|
59
|
+
/** Runtime Assembler:校验一份扁平输入并生成可原子提交的 Snapshot。 */
|
|
86
60
|
|
|
87
61
|
export type { RuntimeDegradation } from "./kernel/degradation";
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
readonly
|
|
99
|
-
readonly
|
|
100
|
-
readonly
|
|
101
|
-
readonly
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
readonly
|
|
109
|
-
readonly
|
|
110
|
-
readonly
|
|
111
|
-
readonly
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
export interface RuntimeExtensionContribution {
|
|
118
|
-
readonly name: string;
|
|
119
|
-
readonly extension: RuntimeExtensionConfig;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* 描述 Agent 对最终 Tool Surface 的可见性约束。
|
|
124
|
-
*
|
|
125
|
-
* Host 只提供策略;Runtime 在唯一 Tool Surface seam 中对所有
|
|
126
|
-
* Port 和 Resource 生成的候选项统一应用。
|
|
127
|
-
*/
|
|
128
|
-
export interface RuntimeToolSurfacePolicy {
|
|
129
|
-
readonly denyPolicy?: RuntimeDenyPolicy;
|
|
130
|
-
readonly allowsTool?: (name: string) => boolean;
|
|
131
|
-
readonly allowsExtension?: (extension: RuntimeExtensionConfig) => boolean;
|
|
132
|
-
}
|
|
133
|
-
|
|
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
|
-
};
|
|
177
|
-
}
|
|
178
|
-
|
|
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>>;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* 汇总一次 Runtime 装配要使用的全部 Plugin。
|
|
205
|
-
*/
|
|
206
|
-
export interface AgentConfig {
|
|
207
|
-
readonly plugins: readonly AgentPlugin[];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* 定义一个只准备声明式结果的 Runtime Plugin。
|
|
212
|
-
*
|
|
213
|
-
* Runtime 内部负责排序、合并、冲突检查和提交。
|
|
214
|
-
*/
|
|
215
|
-
export function definePlugin<K extends PluginKind>(
|
|
216
|
-
spec: AgentPluginSpec<K>,
|
|
217
|
-
): AgentPlugin<K> {
|
|
218
|
-
return Object.freeze({
|
|
219
|
-
kind: spec.kind,
|
|
220
|
-
|
|
221
|
-
async prepare(): Promise<PreparedPlugin<K>> {
|
|
222
|
-
const prepared = await spec.prepare();
|
|
223
|
-
const degradations = Object.freeze(
|
|
224
|
-
prepared.degradations.map((degradation) =>
|
|
225
|
-
Object.freeze({ ...degradation }),
|
|
226
|
-
),
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
return Object.freeze({
|
|
230
|
-
...prepared,
|
|
231
|
-
kind: spec.kind,
|
|
232
|
-
degradations,
|
|
233
|
-
}) as PreparedPlugin<K>;
|
|
234
|
-
},
|
|
235
|
-
}) as AgentPlugin<K>;
|
|
62
|
+
export type {
|
|
63
|
+
RuntimeExtensionContribution,
|
|
64
|
+
RuntimeProfileContribution,
|
|
65
|
+
RuntimeSkillContribution,
|
|
66
|
+
RuntimeToolSurfacePolicy,
|
|
67
|
+
} from "./runtime-definition";
|
|
68
|
+
|
|
69
|
+
/** Host Planner 与 Runtime Assembler 之间的一次性内部 seam。 */
|
|
70
|
+
export interface RuntimeAssemblyInput {
|
|
71
|
+
readonly profile: RuntimeProfileContribution;
|
|
72
|
+
readonly memoryProfile: RuntimeMemoryProfile;
|
|
73
|
+
readonly toolPolicy?: RuntimeToolSurfacePolicy;
|
|
74
|
+
readonly enabledSubagents: readonly string[];
|
|
75
|
+
readonly provider: RuntimeProviderPort;
|
|
76
|
+
readonly platform: RuntimePlatformPort;
|
|
77
|
+
readonly workspace?: WorkspacePort;
|
|
78
|
+
readonly codeExecution?: RuntimeCodeExecutionPort;
|
|
79
|
+
readonly sandbox?: RuntimeSandboxPort;
|
|
80
|
+
readonly memory?: RuntimeMemoryPort;
|
|
81
|
+
readonly hostTools: readonly PiToolCandidate[];
|
|
82
|
+
readonly skills: readonly RuntimeSkillContribution[];
|
|
83
|
+
readonly connectors: readonly RuntimeMcpServer[];
|
|
84
|
+
readonly gateway?: RuntimeGatewayPort;
|
|
85
|
+
readonly extensions: readonly RuntimeExtensionContribution[];
|
|
86
|
+
readonly subagents?: RuntimeSubagentPort;
|
|
87
|
+
readonly schedule?: RuntimeSchedulePort;
|
|
88
|
+
readonly turnEvents?: RuntimeTurnEventsPort;
|
|
89
|
+
readonly commitGuards: readonly (() => Promise<void>)[];
|
|
90
|
+
readonly degradations: readonly RuntimeDegradation[];
|
|
236
91
|
}
|
|
237
92
|
|
|
238
|
-
// #
|
|
239
|
-
|
|
240
|
-
// #region 内部候选契约与装配顺序
|
|
93
|
+
// #region 内部候选契约
|
|
241
94
|
|
|
242
95
|
/**
|
|
243
96
|
* 保存一次已经完成校验、可供 Kernel 使用的 Runtime 结果。
|
|
@@ -259,31 +112,10 @@ export interface RuntimeSnapshot {
|
|
|
259
112
|
export interface RuntimeCandidate {
|
|
260
113
|
readonly snapshot: RuntimeSnapshot;
|
|
261
114
|
readonly commitGuards: readonly (() => Promise<void>)[];
|
|
115
|
+
readonly hooks?: RuntimeAgentHooks<Cloudflare.Env, unknown, never, never>;
|
|
116
|
+
readonly turnEvents?: RuntimeTurnEventsPort;
|
|
262
117
|
}
|
|
263
118
|
|
|
264
|
-
const PLUGIN_ORDER: readonly PluginKind[] = Object.freeze([
|
|
265
|
-
"scope",
|
|
266
|
-
"profile",
|
|
267
|
-
"provider",
|
|
268
|
-
"platform",
|
|
269
|
-
"workspace",
|
|
270
|
-
"sandbox",
|
|
271
|
-
"memory",
|
|
272
|
-
"tool",
|
|
273
|
-
"skill",
|
|
274
|
-
"connector",
|
|
275
|
-
"extension",
|
|
276
|
-
"schedule",
|
|
277
|
-
"subagent",
|
|
278
|
-
"turn-events",
|
|
279
|
-
]);
|
|
280
|
-
|
|
281
|
-
const REQUIRED_PLUGIN_KINDS: readonly PluginKind[] = Object.freeze([
|
|
282
|
-
"profile",
|
|
283
|
-
"provider",
|
|
284
|
-
"platform",
|
|
285
|
-
]);
|
|
286
|
-
|
|
287
119
|
const DISABLED_MEMORY: RuntimeMemoryProfile = Object.freeze({
|
|
288
120
|
enabled: false,
|
|
289
121
|
memoryTokens: 2_000,
|
|
@@ -322,12 +154,8 @@ interface ToolSurfaceInput {
|
|
|
322
154
|
readonly port: RuntimeMemoryPort;
|
|
323
155
|
readonly profile: RuntimeMemoryProfile;
|
|
324
156
|
};
|
|
325
|
-
readonly codeExecution?: RuntimeCodeExecutionPort;
|
|
326
|
-
readonly sandbox?: RuntimeSandboxPort;
|
|
327
157
|
readonly hostTools: readonly PiToolCandidate[];
|
|
328
158
|
readonly skills: readonly RuntimeSkillSourceBinding[];
|
|
329
|
-
readonly schedule?: RuntimeSchedulePort;
|
|
330
|
-
readonly subagents?: RuntimeSubagentPort;
|
|
331
159
|
readonly enabledSubagents: readonly string[];
|
|
332
160
|
readonly webSearch: Parameters<typeof basePiToolCandidates>[0];
|
|
333
161
|
readonly extensions: readonly RuntimeExtensionConfig[];
|
|
@@ -355,50 +183,24 @@ async function createToolSurface(
|
|
|
355
183
|
const browserCandidates = input.platform.browser
|
|
356
184
|
? browserQuickActionPiToolCandidates(input.platform.browser)
|
|
357
185
|
: [];
|
|
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
186
|
const baseCandidates = basePiToolCandidates(input.webSearch);
|
|
375
187
|
const memoryCandidates = input.memory
|
|
376
188
|
? [memoryPiToolCandidate(input.memory.port, input.memory.profile)]
|
|
377
189
|
: [];
|
|
378
190
|
const scriptCandidates = [
|
|
379
191
|
...browserCandidates,
|
|
380
|
-
...workspaceCandidates,
|
|
381
|
-
...executionCandidates,
|
|
382
|
-
...sandboxCandidates,
|
|
383
192
|
...input.hostTools,
|
|
384
|
-
...scheduleCandidates,
|
|
385
|
-
...subagentCandidates,
|
|
386
193
|
...baseCandidates,
|
|
387
194
|
...memoryCandidates,
|
|
388
195
|
].filter(visible);
|
|
389
196
|
const staticCandidates = [
|
|
390
197
|
...browserCandidates,
|
|
391
|
-
...workspaceCandidates,
|
|
392
|
-
...executionCandidates,
|
|
393
|
-
...sandboxCandidates,
|
|
394
198
|
...input.hostTools,
|
|
395
199
|
...(await skillPiToolCandidates(input.skills, {
|
|
396
200
|
loader: input.platform.loader,
|
|
397
201
|
...(input.workspace ? { workspace: input.workspace } : {}),
|
|
398
202
|
tools: scriptCandidates,
|
|
399
203
|
})),
|
|
400
|
-
...scheduleCandidates,
|
|
401
|
-
...subagentCandidates,
|
|
402
204
|
...baseCandidates,
|
|
403
205
|
...memoryCandidates,
|
|
404
206
|
];
|
|
@@ -441,6 +243,7 @@ class RuntimeBuilder {
|
|
|
441
243
|
private profile?: RuntimeProfileContribution;
|
|
442
244
|
private provider?: RuntimeProviderPort;
|
|
443
245
|
private platform?: RuntimePlatformPort;
|
|
246
|
+
private gateway?: RuntimeGatewayPort;
|
|
444
247
|
private workspace?: WorkspacePort;
|
|
445
248
|
private codeExecution?: RuntimeCodeExecutionPort;
|
|
446
249
|
private sandbox?: RuntimeSandboxPort;
|
|
@@ -466,68 +269,36 @@ class RuntimeBuilder {
|
|
|
466
269
|
private readonly commitGuards: Array<() => Promise<void>> = [];
|
|
467
270
|
private readonly degradations: RuntimeDegradation[] = [];
|
|
468
271
|
|
|
469
|
-
merge(
|
|
470
|
-
for (const degradation of
|
|
272
|
+
merge(input: RuntimeAssemblyInput): void {
|
|
273
|
+
for (const degradation of input.degradations) {
|
|
471
274
|
this.reportDegradation(degradation);
|
|
472
275
|
}
|
|
473
|
-
|
|
474
|
-
|
|
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;
|
|
276
|
+
if (!EXECUTION_LEVELS.includes(input.profile.executionLevel)) {
|
|
277
|
+
throw new Error("Runtime execution level is invalid");
|
|
530
278
|
}
|
|
279
|
+
this.profile = input.profile;
|
|
280
|
+
this.provider = input.provider;
|
|
281
|
+
this.platform = input.platform;
|
|
282
|
+
this.workspace = input.workspace;
|
|
283
|
+
this.codeExecution = input.codeExecution;
|
|
284
|
+
this.sandbox = input.sandbox;
|
|
285
|
+
this.memoryProfile = input.memoryProfile;
|
|
286
|
+
this.memory = input.memory;
|
|
287
|
+
this.hostTools.push(...input.hostTools);
|
|
288
|
+
this.toolPolicy = input.toolPolicy;
|
|
289
|
+
for (const skill of input.skills) this.addSkill(skill);
|
|
290
|
+
for (const connector of input.connectors) this.addConnector(connector);
|
|
291
|
+
this.gateway = input.gateway;
|
|
292
|
+
for (const { name, extension } of input.extensions) {
|
|
293
|
+
this.addExtension(name, extension);
|
|
294
|
+
}
|
|
295
|
+
this.schedule = input.schedule;
|
|
296
|
+
for (const name of input.enabledSubagents) {
|
|
297
|
+
this.enabledSubagents.add(requiredName(name, "Subagent"));
|
|
298
|
+
}
|
|
299
|
+
this.subagents = input.subagents;
|
|
300
|
+
this.turnEvents = input.turnEvents;
|
|
301
|
+
this.commitGuards.push(...input.commitGuards);
|
|
531
302
|
}
|
|
532
303
|
|
|
533
304
|
private addSkill(skill: RuntimeSkillContribution): void {
|
|
@@ -614,17 +385,17 @@ class RuntimeBuilder {
|
|
|
614
385
|
// #region RuntimeBuilder 校验与候选生成
|
|
615
386
|
|
|
616
387
|
// 作用:校验全部声明,并生成一个不可变候选 Runtime。
|
|
617
|
-
//
|
|
388
|
+
// 调用:扁平 Assembly Input 合并完成后调用一次。
|
|
618
389
|
// 原因:所有交叉约束都在这里通过后才返回候选,旧 Snapshot 不会半更新。
|
|
619
390
|
async build(): Promise<RuntimeCandidate> {
|
|
620
391
|
if (!this.profile) {
|
|
621
|
-
throw new Error("Runtime
|
|
392
|
+
throw new Error("Runtime assembly did not configure a profile");
|
|
622
393
|
}
|
|
623
394
|
if (!this.platform) {
|
|
624
|
-
throw new Error("Runtime
|
|
395
|
+
throw new Error("Runtime assembly did not bind a platform");
|
|
625
396
|
}
|
|
626
397
|
if (!this.provider) {
|
|
627
|
-
throw new Error("Runtime
|
|
398
|
+
throw new Error("Runtime assembly did not bind a provider");
|
|
628
399
|
}
|
|
629
400
|
if (!this.profile.model.trim()) {
|
|
630
401
|
throw new Error("Runtime model must not be empty");
|
|
@@ -653,17 +424,7 @@ class RuntimeBuilder {
|
|
|
653
424
|
assertMemoryProfile(this.memoryProfile);
|
|
654
425
|
if (this.memoryProfile.enabled && (!this.workspace || !this.memory)) {
|
|
655
426
|
throw new Error(
|
|
656
|
-
"Enabled Runtime memory requires Workspace and Memory
|
|
657
|
-
);
|
|
658
|
-
}
|
|
659
|
-
if (this.sandbox && !this.workspace) {
|
|
660
|
-
throw new Error(
|
|
661
|
-
"Runtime Sandbox requires a persistent Workspace port",
|
|
662
|
-
);
|
|
663
|
-
}
|
|
664
|
-
if (this.enabledSubagents.size > 0 && !this.subagents) {
|
|
665
|
-
throw new Error(
|
|
666
|
-
"Enabled Runtime Subagents require a Subagent port",
|
|
427
|
+
"Enabled Runtime memory requires Workspace and Memory bindings",
|
|
667
428
|
);
|
|
668
429
|
}
|
|
669
430
|
const profile = freezeRuntimeProfile({
|
|
@@ -713,12 +474,8 @@ class RuntimeBuilder {
|
|
|
713
474
|
...(this.memoryProfile.enabled && this.memory
|
|
714
475
|
? { memory: { port: this.memory, profile: this.memoryProfile } }
|
|
715
476
|
: {}),
|
|
716
|
-
...(this.codeExecution ? { codeExecution: this.codeExecution } : {}),
|
|
717
|
-
...(this.sandbox ? { sandbox: this.sandbox } : {}),
|
|
718
477
|
hostTools: this.hostTools,
|
|
719
478
|
skills: skillSources,
|
|
720
|
-
...(this.schedule ? { schedule: this.schedule } : {}),
|
|
721
|
-
...(this.subagents ? { subagents: this.subagents } : {}),
|
|
722
479
|
enabledSubagents: [...this.enabledSubagents],
|
|
723
480
|
webSearch,
|
|
724
481
|
extensions: [...this.extensions.values()],
|
|
@@ -730,6 +487,7 @@ class RuntimeBuilder {
|
|
|
730
487
|
const bindings: RuntimeBindings = Object.freeze({
|
|
731
488
|
provider,
|
|
732
489
|
platform: Object.freeze({ ...this.platform }),
|
|
490
|
+
...(this.gateway ? { gateway: this.gateway } : {}),
|
|
733
491
|
...(this.workspace ? { workspace: this.workspace } : {}),
|
|
734
492
|
...(this.memoryProfile.enabled && this.memory
|
|
735
493
|
? { memory: this.memory }
|
|
@@ -764,75 +522,23 @@ class RuntimeBuilder {
|
|
|
764
522
|
|
|
765
523
|
}
|
|
766
524
|
|
|
767
|
-
// 作用:检查 Plugin kind 合法、唯一,并包含所有必需能力。
|
|
768
|
-
// 调用:任何 prepare 启动前由 `prepareRuntimeCandidate` 调用。
|
|
769
|
-
// 原因:先校验结构可避免为注定失败的配置执行外部读取。
|
|
770
|
-
function validatePluginKinds(
|
|
771
|
-
plugins: readonly AgentPlugin[],
|
|
772
|
-
): void {
|
|
773
|
-
const kinds = new Set<PluginKind>();
|
|
774
|
-
const knownKinds = new Set(PLUGIN_ORDER);
|
|
775
|
-
|
|
776
|
-
for (const plugin of plugins) {
|
|
777
|
-
if (!knownKinds.has(plugin.kind)) {
|
|
778
|
-
throw new Error(`Unknown Agent Plugin kind: ${plugin.kind}`);
|
|
779
|
-
}
|
|
780
|
-
if (kinds.has(plugin.kind)) {
|
|
781
|
-
throw new Error(
|
|
782
|
-
`Duplicate Agent Plugin kind: ${plugin.kind}`,
|
|
783
|
-
);
|
|
784
|
-
}
|
|
785
|
-
kinds.add(plugin.kind);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
for (const required of REQUIRED_PLUGIN_KINDS) {
|
|
789
|
-
if (!kinds.has(required)) {
|
|
790
|
-
throw new Error(
|
|
791
|
-
`Missing required Agent Plugin: ${required}`,
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
|
|
797
525
|
/**
|
|
798
526
|
* 在不改动当前 Runtime 的前提下生成一个隔离候选。
|
|
799
527
|
*
|
|
800
528
|
* @remarks
|
|
801
529
|
* `AgentRuntimeKernel` 在初始化或重载时调用它。
|
|
802
530
|
*
|
|
803
|
-
*
|
|
531
|
+
* 任何合并、校验或 Tool Surface 构建失败都不会产生 commit。
|
|
804
532
|
*
|
|
805
533
|
* 该函数有意不从包入口导出,提交生命周期只能由 Kernel 控制。
|
|
806
534
|
*
|
|
807
535
|
* @internal
|
|
808
536
|
*/
|
|
809
537
|
export async function prepareRuntimeCandidate(
|
|
810
|
-
|
|
538
|
+
input: RuntimeAssemblyInput,
|
|
811
539
|
): Promise<RuntimeCandidate> {
|
|
812
|
-
validatePluginKinds(config.plugins);
|
|
813
|
-
|
|
814
|
-
const prepared = await Promise.all(
|
|
815
|
-
config.plugins.map(async (plugin) => {
|
|
816
|
-
const result = await plugin.prepare();
|
|
817
|
-
if (result.kind !== plugin.kind) {
|
|
818
|
-
throw new Error(
|
|
819
|
-
`Prepared Agent Plugin kind mismatch: expected ${plugin.kind}, got ${result.kind}`,
|
|
820
|
-
);
|
|
821
|
-
}
|
|
822
|
-
return result;
|
|
823
|
-
}),
|
|
824
|
-
);
|
|
825
|
-
const byKind = new Map(
|
|
826
|
-
prepared.map((plugin) => [plugin.kind, plugin]),
|
|
827
|
-
);
|
|
828
540
|
const builder = new RuntimeBuilder();
|
|
829
|
-
|
|
830
|
-
for (const kind of PLUGIN_ORDER) {
|
|
831
|
-
const plugin = byKind.get(kind);
|
|
832
|
-
if (!plugin) continue;
|
|
833
|
-
builder.merge(plugin);
|
|
834
|
-
}
|
|
835
|
-
|
|
541
|
+
builder.merge(input);
|
|
836
542
|
return builder.build();
|
|
837
543
|
}
|
|
838
544
|
|
|
@@ -846,15 +552,242 @@ export async function prepareRuntimeCandidate(
|
|
|
846
552
|
*
|
|
847
553
|
* @internal
|
|
848
554
|
*/
|
|
849
|
-
export async function
|
|
850
|
-
|
|
555
|
+
export async function assembleRuntime(
|
|
556
|
+
input: RuntimeAssemblyInput,
|
|
851
557
|
commit: (snapshot: RuntimeSnapshot) => void,
|
|
852
558
|
): Promise<void> {
|
|
853
|
-
const candidate = await prepareRuntimeCandidate(
|
|
559
|
+
const candidate = await prepareRuntimeCandidate(input);
|
|
854
560
|
for (const guard of candidate.commitGuards) {
|
|
855
561
|
await guard();
|
|
856
562
|
}
|
|
857
563
|
commit(candidate.snapshot);
|
|
858
564
|
}
|
|
859
565
|
|
|
566
|
+
export function toolRegistryPiToolCandidates(
|
|
567
|
+
registry: ToolRegistry,
|
|
568
|
+
settings?: Pick<RuntimeSettings, "toolPolicy">,
|
|
569
|
+
): PiToolCandidate[] {
|
|
570
|
+
const deny = new Set(settings?.toolPolicy?.denyPolicy?.deny ?? []);
|
|
571
|
+
const allowsTool = settings?.toolPolicy?.allowsTool;
|
|
572
|
+
const candidates: PiToolCandidate[] = [];
|
|
573
|
+
for (const [name, spec] of Object.entries(registry)) {
|
|
574
|
+
if (deny.has(name)) continue;
|
|
575
|
+
if (allowsTool?.(name) === false) continue;
|
|
576
|
+
const normalized = requiredName(name, "Platform Tool");
|
|
577
|
+
candidates.push(Object.freeze({
|
|
578
|
+
owner: "platform",
|
|
579
|
+
authorized: true,
|
|
580
|
+
requiredExecutionLevel: spec.requiredExecutionLevel,
|
|
581
|
+
...(spec.alwaysRequiresApproval
|
|
582
|
+
? { alwaysRequiresApproval: true }
|
|
583
|
+
: {}),
|
|
584
|
+
tool: Object.freeze({
|
|
585
|
+
name: normalized,
|
|
586
|
+
label: spec.label,
|
|
587
|
+
description: spec.description,
|
|
588
|
+
parameters: spec.parameters,
|
|
589
|
+
async execute(
|
|
590
|
+
toolCallId: string,
|
|
591
|
+
input: unknown,
|
|
592
|
+
signal?: AbortSignal,
|
|
593
|
+
) {
|
|
594
|
+
const result = await spec.execute(input, {
|
|
595
|
+
toolCallId,
|
|
596
|
+
signal: signal ?? new AbortController().signal,
|
|
597
|
+
});
|
|
598
|
+
if (
|
|
599
|
+
result != null &&
|
|
600
|
+
typeof result === "object" &&
|
|
601
|
+
"content" in result &&
|
|
602
|
+
Array.isArray((result as { content?: unknown }).content)
|
|
603
|
+
) {
|
|
604
|
+
return result as import("@earendil-works/pi-agent-core").AgentToolResult<unknown>;
|
|
605
|
+
}
|
|
606
|
+
let text: string;
|
|
607
|
+
try {
|
|
608
|
+
text = JSON.stringify(result) ?? String(result);
|
|
609
|
+
} catch {
|
|
610
|
+
text = String(result);
|
|
611
|
+
}
|
|
612
|
+
return {
|
|
613
|
+
content: [{ type: "text" as const, text }],
|
|
614
|
+
details: result,
|
|
615
|
+
};
|
|
616
|
+
},
|
|
617
|
+
} as AgentTool<any, any>),
|
|
618
|
+
}));
|
|
619
|
+
}
|
|
620
|
+
return candidates;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function hooksToTurnEventsPort<
|
|
624
|
+
Env extends Cloudflare.Env,
|
|
625
|
+
Config,
|
|
626
|
+
Command,
|
|
627
|
+
Change,
|
|
628
|
+
>(
|
|
629
|
+
ctx: AssembleRuntimeSnapshotInput<Env, Config, Command, Change>["ctx"],
|
|
630
|
+
hooks?: RuntimeAgentHooks<Env, Config, Command, Change>,
|
|
631
|
+
): RuntimeTurnEventsPort | undefined {
|
|
632
|
+
if (!hooks) return undefined;
|
|
633
|
+
if (
|
|
634
|
+
!hooks.onTurnEnd &&
|
|
635
|
+
!hooks.onModelUsage &&
|
|
636
|
+
!hooks.onToolSettled &&
|
|
637
|
+
!hooks.onApproval &&
|
|
638
|
+
!hooks.onActivityChanged &&
|
|
639
|
+
!hooks.onSubmissionTerminal
|
|
640
|
+
) {
|
|
641
|
+
return undefined;
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
onResponse: hooks.onTurnEnd
|
|
645
|
+
? (messages) => hooks.onTurnEnd!(ctx, messages)
|
|
646
|
+
: async () => undefined,
|
|
647
|
+
...(hooks.onModelUsage ? { onModelUsage: hooks.onModelUsage } : {}),
|
|
648
|
+
...(hooks.onToolSettled ? { onToolSettled: hooks.onToolSettled } : {}),
|
|
649
|
+
...(hooks.onApproval ? { onApproval: hooks.onApproval } : {}),
|
|
650
|
+
...(hooks.onActivityChanged
|
|
651
|
+
? { onActivityChanged: hooks.onActivityChanged }
|
|
652
|
+
: {}),
|
|
653
|
+
...(hooks.onSubmissionTerminal
|
|
654
|
+
? { onSubmissionTerminal: hooks.onSubmissionTerminal }
|
|
655
|
+
: {}),
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* 从 Config、Tool 和已加载 Resource 装配 Runtime 候选 Snapshot。
|
|
661
|
+
*
|
|
662
|
+
* @internal
|
|
663
|
+
*/
|
|
664
|
+
export async function assembleRuntimeSnapshot<
|
|
665
|
+
Env extends Cloudflare.Env,
|
|
666
|
+
Config,
|
|
667
|
+
Command = never,
|
|
668
|
+
Change = never,
|
|
669
|
+
>(
|
|
670
|
+
input: AssembleRuntimeSnapshotInput<Env, Config, Command, Change>,
|
|
671
|
+
): Promise<RuntimeCandidate> {
|
|
672
|
+
const resources = input.resources;
|
|
673
|
+
const toolAssembly = input.tools;
|
|
674
|
+
const settings = resources.settings;
|
|
675
|
+
const provider = resources.provider;
|
|
676
|
+
let profile = settings.profile;
|
|
677
|
+
if (input.hooks?.profileOverrides) {
|
|
678
|
+
const overrides = await input.hooks.profileOverrides(
|
|
679
|
+
input.ctx,
|
|
680
|
+
input.config,
|
|
681
|
+
);
|
|
682
|
+
if (overrides.systemPrompt !== undefined) {
|
|
683
|
+
profile = { ...profile, systemPrompt: overrides.systemPrompt };
|
|
684
|
+
}
|
|
685
|
+
if (overrides.executionLevel !== undefined) {
|
|
686
|
+
profile = { ...profile, executionLevel: overrides.executionLevel };
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const hostTools = toolRegistryPiToolCandidates(
|
|
691
|
+
toolAssembly.tools,
|
|
692
|
+
settings,
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
const commitGuards: Array<() => Promise<void>> = [];
|
|
696
|
+
if (toolAssembly.commitGuard) commitGuards.push(toolAssembly.commitGuard);
|
|
697
|
+
if (input.hooks?.beforeCommit) {
|
|
698
|
+
for (const guard of input.hooks.beforeCommit) {
|
|
699
|
+
commitGuards.push(() => guard(input.ctx, input.config));
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const platform: RuntimePlatformPort = input.hooks?.gateTool
|
|
704
|
+
? Object.freeze({
|
|
705
|
+
...resources.platform,
|
|
706
|
+
gateTool: (request: {
|
|
707
|
+
toolCallId: string;
|
|
708
|
+
toolName: string;
|
|
709
|
+
input: unknown;
|
|
710
|
+
requiredExecutionLevel: import("./lib/execution-level").ExecutionLevel;
|
|
711
|
+
signal: AbortSignal;
|
|
712
|
+
}) => input.hooks!.gateTool!(request),
|
|
713
|
+
})
|
|
714
|
+
: resources.platform;
|
|
715
|
+
|
|
716
|
+
const memoryProfile =
|
|
717
|
+
toolAssembly.memoryProfile ?? settings.memoryProfile;
|
|
718
|
+
const enabledSubagents =
|
|
719
|
+
toolAssembly.enabledSubagents ?? settings.enabledSubagents;
|
|
720
|
+
const turnEvents = hooksToTurnEventsPort(input.ctx, input.hooks);
|
|
721
|
+
|
|
722
|
+
const toolPolicy: RuntimeToolSurfacePolicy | undefined =
|
|
723
|
+
settings.toolPolicy || toolAssembly.surfacePolicy
|
|
724
|
+
? {
|
|
725
|
+
...(settings.toolPolicy?.denyPolicy
|
|
726
|
+
? { denyPolicy: settings.toolPolicy.denyPolicy }
|
|
727
|
+
: {}),
|
|
728
|
+
...(settings.toolPolicy?.allowsTool
|
|
729
|
+
? { allowsTool: settings.toolPolicy.allowsTool }
|
|
730
|
+
: {}),
|
|
731
|
+
...(settings.toolPolicy?.allowsExtension
|
|
732
|
+
? { allowsExtension: settings.toolPolicy.allowsExtension }
|
|
733
|
+
: {}),
|
|
734
|
+
...(toolAssembly.surfacePolicy?.allowsTool
|
|
735
|
+
? { allowsTool: toolAssembly.surfacePolicy.allowsTool }
|
|
736
|
+
: {}),
|
|
737
|
+
...(toolAssembly.surfacePolicy?.allowsExtension
|
|
738
|
+
? { allowsExtension: toolAssembly.surfacePolicy.allowsExtension }
|
|
739
|
+
: {}),
|
|
740
|
+
}
|
|
741
|
+
: undefined;
|
|
742
|
+
|
|
743
|
+
const assemblyInput: RuntimeAssemblyInput = {
|
|
744
|
+
profile,
|
|
745
|
+
memoryProfile,
|
|
746
|
+
...(toolPolicy ? { toolPolicy } : {}),
|
|
747
|
+
enabledSubagents: [...enabledSubagents],
|
|
748
|
+
provider,
|
|
749
|
+
platform,
|
|
750
|
+
...(toolAssembly.bindings?.workspace
|
|
751
|
+
? { workspace: toolAssembly.bindings.workspace }
|
|
752
|
+
: {}),
|
|
753
|
+
...(memoryProfile.enabled && toolAssembly.bindings?.memory
|
|
754
|
+
? { memory: toolAssembly.bindings.memory }
|
|
755
|
+
: {}),
|
|
756
|
+
hostTools,
|
|
757
|
+
skills: resources.skills,
|
|
758
|
+
connectors: resources.connectors.servers,
|
|
759
|
+
...(resources.connectors.gateway
|
|
760
|
+
? { gateway: resources.connectors.gateway }
|
|
761
|
+
: {}),
|
|
762
|
+
extensions: resources.extensions,
|
|
763
|
+
...(turnEvents ? { turnEvents } : {}),
|
|
764
|
+
commitGuards: [],
|
|
765
|
+
degradations: [
|
|
766
|
+
...(toolAssembly.degradations ?? []),
|
|
767
|
+
...(resources.degradations ?? []),
|
|
768
|
+
...resources.connectors.degradations,
|
|
769
|
+
],
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
const candidate = await prepareRuntimeCandidate(assemblyInput);
|
|
773
|
+
return Object.freeze({
|
|
774
|
+
snapshot: candidate.snapshot,
|
|
775
|
+
commitGuards: Object.freeze([
|
|
776
|
+
...candidate.commitGuards,
|
|
777
|
+
...commitGuards,
|
|
778
|
+
]),
|
|
779
|
+
...(input.hooks
|
|
780
|
+
? {
|
|
781
|
+
hooks: input.hooks as unknown as RuntimeAgentHooks<
|
|
782
|
+
Cloudflare.Env,
|
|
783
|
+
unknown,
|
|
784
|
+
never,
|
|
785
|
+
never
|
|
786
|
+
>,
|
|
787
|
+
}
|
|
788
|
+
: {}),
|
|
789
|
+
...(turnEvents ? { turnEvents } : {}),
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
|
|
860
793
|
// #endregion
|