@springbrand/agent-runtime 0.1.3-alpha.4 → 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/index.ts +49 -7
- 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 +4 -2
- package/src/pi/runtime-adapter/index.ts +6 -2
- package/src/pi/tool/base.ts +17 -0
- package/src/pi/tool/core.ts +13 -0
- 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/runtime-agent-context.ts +112 -0
- package/src/runtime-agent.ts +429 -315
- package/src/runtime-assembler.ts +249 -99
- package/src/runtime-definition.ts +173 -0
- package/src/runtime.ts +139 -12
- package/src/tool-registry.ts +143 -0
package/src/runtime.ts
CHANGED
|
@@ -49,8 +49,11 @@ import { RuntimeLoadTracker } from "./kernel/runtime-load";
|
|
|
49
49
|
import {
|
|
50
50
|
prepareRuntimeCandidate,
|
|
51
51
|
type RuntimeAssemblyInput,
|
|
52
|
+
type RuntimeCandidate,
|
|
52
53
|
type RuntimeSnapshot,
|
|
53
54
|
} from "./runtime-assembler";
|
|
55
|
+
import type { RuntimeAgentHooks } from "./runtime-definition";
|
|
56
|
+
import type { RuntimeTurnEventsPort } from "./kernel/bindings";
|
|
54
57
|
import { connectConfiguredMcpServers } from "./lib/mcp";
|
|
55
58
|
import { installConsoleSink } from "./lib/telemetry-dev";
|
|
56
59
|
import {
|
|
@@ -62,6 +65,7 @@ import {
|
|
|
62
65
|
type PiCanonicalTranscriptSnapshot,
|
|
63
66
|
type PiChatRecoveryData,
|
|
64
67
|
type UIChatRequestBody,
|
|
68
|
+
type RequestedCapability,
|
|
65
69
|
type PiDurableMutation,
|
|
66
70
|
type PiRecoveryCommand,
|
|
67
71
|
type PiRecoveryDecision,
|
|
@@ -221,6 +225,44 @@ function userContentKey(message: PiCanonicalUserInput): string {
|
|
|
221
225
|
);
|
|
222
226
|
}
|
|
223
227
|
|
|
228
|
+
function requestedCapabilitiesOf(metadata: unknown): RequestedCapability[] {
|
|
229
|
+
if (metadata === null || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
const record = metadata as Record<string, unknown>;
|
|
233
|
+
if (!("requestedCapabilities" in record)) return [];
|
|
234
|
+
if (!Array.isArray(record.requestedCapabilities)) {
|
|
235
|
+
throw new Error("requestedCapabilities must be an array");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const result: RequestedCapability[] = [];
|
|
239
|
+
const seen = new Set<string>();
|
|
240
|
+
for (const value of record.requestedCapabilities) {
|
|
241
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
242
|
+
throw new Error("requestedCapabilities contains an invalid capability");
|
|
243
|
+
}
|
|
244
|
+
const capability = value as Record<string, unknown>;
|
|
245
|
+
if (
|
|
246
|
+
(capability.kind !== "skill" && capability.kind !== "plan") ||
|
|
247
|
+
typeof capability.name !== "string" ||
|
|
248
|
+
!capability.name.trim() ||
|
|
249
|
+
typeof capability.label !== "string" ||
|
|
250
|
+
!capability.label.trim()
|
|
251
|
+
) {
|
|
252
|
+
throw new Error("requestedCapabilities contains an invalid capability");
|
|
253
|
+
}
|
|
254
|
+
const key = `${capability.kind}:${capability.name}`;
|
|
255
|
+
if (seen.has(key)) continue;
|
|
256
|
+
seen.add(key);
|
|
257
|
+
result.push({
|
|
258
|
+
kind: capability.kind,
|
|
259
|
+
name: capability.name,
|
|
260
|
+
label: capability.label,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
}
|
|
265
|
+
|
|
224
266
|
interface PendingTemporaryAgentApproval {
|
|
225
267
|
receipt: ApprovalReceipt;
|
|
226
268
|
resolve(decision: TemporaryAgentApprovalDecision): void;
|
|
@@ -257,6 +299,8 @@ export abstract class AgentRuntimeKernel<
|
|
|
257
299
|
private runtimeRevision?: string;
|
|
258
300
|
private runtimePi?: PreparedPiRuntime;
|
|
259
301
|
private runtimeGatewaySession?: RuntimeGatewaySession;
|
|
302
|
+
private runtimeTurnEvents?: RuntimeTurnEventsPort;
|
|
303
|
+
private runtimeHooks?: RuntimeAgentHooks;
|
|
260
304
|
private piAdapter?: PiRuntimeAdapter;
|
|
261
305
|
private readonly transcript: PiRuntimeTranscript;
|
|
262
306
|
private readonly submissions: SubmissionLifecycle<
|
|
@@ -462,11 +506,21 @@ export abstract class AgentRuntimeKernel<
|
|
|
462
506
|
// 调用:生成 Agent 在首次启动或显式重载 Runtime key 时调用。
|
|
463
507
|
// 原因:先完整 prepare 再替换 Snapshot,且活跃 Turn 期间禁止换 revision,可避免半装配和恢复时能力漂移。
|
|
464
508
|
protected async initConfig(input: RuntimeAssemblyInput): Promise<void> {
|
|
465
|
-
const previous = this.runtimeSnapshot;
|
|
466
|
-
this.runtimeLoad.advance("assembly");
|
|
467
509
|
const candidate = await prepareRuntimeCandidate(input);
|
|
468
|
-
|
|
510
|
+
await this.initCandidate(candidate);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
private turnEventsPort(): RuntimeTurnEventsPort | undefined {
|
|
514
|
+
return this.runtimeTurnEvents ?? this.runtimeSnapshot?.bindings.turnEvents;
|
|
515
|
+
}
|
|
469
516
|
|
|
517
|
+
protected async initCandidate(candidate: RuntimeCandidate): Promise<void> {
|
|
518
|
+
this.runtimeTurnEvents =
|
|
519
|
+
candidate.turnEvents ?? candidate.snapshot.bindings.turnEvents;
|
|
520
|
+
this.runtimeHooks = candidate.hooks;
|
|
521
|
+
const previous = this.runtimeSnapshot;
|
|
522
|
+
const candidateSnapshot = candidate.snapshot;
|
|
523
|
+
this.runtimeLoad.advance("assembly");
|
|
470
524
|
this.runtimeLoad.advance("mcp");
|
|
471
525
|
await connectConfiguredMcpServers(
|
|
472
526
|
this,
|
|
@@ -601,7 +655,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
601
655
|
async (created) => {
|
|
602
656
|
await onCreated?.();
|
|
603
657
|
try {
|
|
604
|
-
await this.
|
|
658
|
+
await this.turnEventsPort()?.onApproval?.({
|
|
605
659
|
submissionId: submission.submissionId,
|
|
606
660
|
approvalExecutionId: created.executionId,
|
|
607
661
|
});
|
|
@@ -727,7 +781,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
727
781
|
}
|
|
728
782
|
|
|
729
783
|
private async drainRuntimeEvents(idempotentRetry = true): Promise<void> {
|
|
730
|
-
const turnEvents = this.
|
|
784
|
+
const turnEvents = this.turnEventsPort();
|
|
731
785
|
if (!turnEvents) return;
|
|
732
786
|
|
|
733
787
|
let failed = false;
|
|
@@ -862,6 +916,41 @@ export abstract class AgentRuntimeKernel<
|
|
|
862
916
|
return this.runtimeSnapshot;
|
|
863
917
|
}
|
|
864
918
|
|
|
919
|
+
private async normalizeUIUserInput(
|
|
920
|
+
message: UIMessage & { role: "user" },
|
|
921
|
+
): Promise<PiCanonicalUserInput> {
|
|
922
|
+
const capabilities = requestedCapabilitiesOf(message.metadata);
|
|
923
|
+
if (capabilities.length === 0) return this.pi.normalizeUserInput(message);
|
|
924
|
+
|
|
925
|
+
await this.ensureRuntimeReady();
|
|
926
|
+
const installedSkills = new Set(
|
|
927
|
+
this.assembly().bindings.skills.sources.map(({ name }) => name),
|
|
928
|
+
);
|
|
929
|
+
const context: string[] = [];
|
|
930
|
+
for (const capability of capabilities) {
|
|
931
|
+
if (capability.kind === "skill") {
|
|
932
|
+
if (!installedSkills.has(capability.name)) {
|
|
933
|
+
throw new Error(
|
|
934
|
+
`Requested Skill is not installed: ${capability.name}`,
|
|
935
|
+
);
|
|
936
|
+
}
|
|
937
|
+
context.push(
|
|
938
|
+
`requested capability: skill/${capability.name}`,
|
|
939
|
+
`required action: call activate_skill for "${capability.name}" before handling the task`,
|
|
940
|
+
);
|
|
941
|
+
continue;
|
|
942
|
+
}
|
|
943
|
+
if (capability.name !== "plan") {
|
|
944
|
+
throw new Error(`Unknown plan capability: ${capability.name}`);
|
|
945
|
+
}
|
|
946
|
+
context.push(
|
|
947
|
+
"requested capability: plan/plan",
|
|
948
|
+
"required action: call update_plan with the complete plan before other work, then wait for user confirmation before execution",
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
return this.pi.normalizeUserInput(message, context.join("\n"));
|
|
952
|
+
}
|
|
953
|
+
|
|
865
954
|
// 作用:把当前已安装的 Runtime Snapshot 投影成可序列化的调试视图。
|
|
866
955
|
// 调用:Session facet 的 `getRuntimeAssembly` RPC。
|
|
867
956
|
// 原因:UI 需要读取真实装配结果,而不是上层配置声明。
|
|
@@ -2246,7 +2335,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2246
2335
|
messages,
|
|
2247
2336
|
}),
|
|
2248
2337
|
);
|
|
2249
|
-
const events = this.
|
|
2338
|
+
const events = this.turnEventsPort();
|
|
2250
2339
|
if (events) {
|
|
2251
2340
|
try {
|
|
2252
2341
|
await events.onResponse(
|
|
@@ -2395,7 +2484,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2395
2484
|
ReturnType<AgentRuntimeKernel["submitMessage"]>
|
|
2396
2485
|
>;
|
|
2397
2486
|
try {
|
|
2398
|
-
const normalized = this.
|
|
2487
|
+
const normalized = await this.normalizeUIUserInput(latest);
|
|
2399
2488
|
submitted = await this.submitMessage(normalized, {
|
|
2400
2489
|
requestId: event.id,
|
|
2401
2490
|
idempotencyKey: event.id,
|
|
@@ -2480,6 +2569,18 @@ export abstract class AgentRuntimeKernel<
|
|
|
2480
2569
|
return this.transcript.browserMessages();
|
|
2481
2570
|
}
|
|
2482
2571
|
|
|
2572
|
+
/** 读取当前 canonical transcript 中最后一条助手文本。 */
|
|
2573
|
+
protected async latestAssistantText(): Promise<string | undefined> {
|
|
2574
|
+
const message = [...await this.transcript.canonicalMessages()]
|
|
2575
|
+
.reverse()
|
|
2576
|
+
.find((entry): entry is AssistantMessage => entry.role === "assistant");
|
|
2577
|
+
const text = message?.content
|
|
2578
|
+
.flatMap((part) => part.type === "text" ? [part.text] : [])
|
|
2579
|
+
.join("")
|
|
2580
|
+
.trim();
|
|
2581
|
+
return text || undefined;
|
|
2582
|
+
}
|
|
2583
|
+
|
|
2483
2584
|
// #endregion
|
|
2484
2585
|
|
|
2485
2586
|
// #region Runtime Extension Host 回环端口
|
|
@@ -2701,9 +2802,18 @@ export abstract class AgentRuntimeKernel<
|
|
|
2701
2802
|
};
|
|
2702
2803
|
}
|
|
2703
2804
|
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2805
|
+
let userMessage: PiCanonicalUserInput;
|
|
2806
|
+
try {
|
|
2807
|
+
userMessage = await this.normalizeUIUserInput(
|
|
2808
|
+
message as UIMessage & { role: "user" },
|
|
2809
|
+
);
|
|
2810
|
+
} catch (error) {
|
|
2811
|
+
return {
|
|
2812
|
+
kind: "rejected",
|
|
2813
|
+
code: "invalid_message",
|
|
2814
|
+
message: errorText(error),
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2707
2817
|
// 停在 interaction park 上的 Turn 一律按 steer 处理,哪怕客户端发的是 enqueue:
|
|
2708
2818
|
// enqueue 要等本 Turn 结束,而本 Turn 正在等一个永远不会来的答案 —— 死锁。
|
|
2709
2819
|
const parked = this.findInteractionParkedSubmission();
|
|
@@ -3194,6 +3304,24 @@ export abstract class AgentRuntimeKernel<
|
|
|
3194
3304
|
await this.broadcastApprovals();
|
|
3195
3305
|
}
|
|
3196
3306
|
|
|
3307
|
+
async _cfDetachedNotifyFinish(
|
|
3308
|
+
run: AgentToolRunInfo,
|
|
3309
|
+
result: AgentToolLifecycleResult,
|
|
3310
|
+
): Promise<void> {
|
|
3311
|
+
const outcome = result.status === "completed"
|
|
3312
|
+
? result.summary ?? "Completed without a result."
|
|
3313
|
+
: result.error ?? `Background run ${result.status}.`;
|
|
3314
|
+
await this.submitPrompt(
|
|
3315
|
+
[
|
|
3316
|
+
"A background sub-agent run has finished.",
|
|
3317
|
+
`runId: ${run.runId}`,
|
|
3318
|
+
`status: ${result.status}`,
|
|
3319
|
+
`result: ${outcome}`,
|
|
3320
|
+
].join("\n"),
|
|
3321
|
+
{ idempotencyKey: `detached-agent-tool:${run.runId}:${result.status}` },
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3197
3325
|
// 作用:把审批、队列和 Session 活动投影到 Agent 可广播状态。
|
|
3198
3326
|
// 调用:启动、准入、审批变化、interaction 变化、子运行变化和 Turn 完成时调用。
|
|
3199
3327
|
// 原因:这些都是可重建的 UI 投影,相同内容不重复 `setState`,投影失败也不能阻断执行。
|
|
@@ -3306,8 +3434,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
3306
3434
|
turn,
|
|
3307
3435
|
});
|
|
3308
3436
|
}
|
|
3309
|
-
const projection = this.
|
|
3310
|
-
?.onActivityChanged?.(nextActivity);
|
|
3437
|
+
const projection = this.turnEventsPort()?.onActivityChanged?.(nextActivity);
|
|
3311
3438
|
if (projection) {
|
|
3312
3439
|
this.ctx.waitUntil(
|
|
3313
3440
|
projection.catch(() => undefined),
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { ExecutionLevel } from "./lib/execution-level";
|
|
2
|
+
import type {
|
|
3
|
+
RuntimeMemoryPort,
|
|
4
|
+
WorkspacePort,
|
|
5
|
+
} from "./kernel/bindings";
|
|
6
|
+
import type { RuntimeExtensionConfig } from "./kernel/extensions";
|
|
7
|
+
import type { RuntimeDegradation } from "./kernel/degradation";
|
|
8
|
+
import type { PiToolCandidate } from "./pi/tool/compiler";
|
|
9
|
+
|
|
10
|
+
/** Tool Surface 筛选策略(不含 Manifest deny 列表)。 */
|
|
11
|
+
export interface ToolSurfaceSelectionPolicy {
|
|
12
|
+
readonly allowsTool?: (name: string) => boolean;
|
|
13
|
+
readonly allowsExtension?: (extension: RuntimeExtensionConfig) => boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** 模型调用 Tool 时传给 `execute` 的上下文。 */
|
|
17
|
+
export interface ToolContext {
|
|
18
|
+
readonly toolCallId: string;
|
|
19
|
+
readonly signal: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Definition 作者声明的一个 Tool。 */
|
|
23
|
+
export interface ToolSpec {
|
|
24
|
+
readonly label: string;
|
|
25
|
+
readonly description: string;
|
|
26
|
+
readonly parameters: unknown;
|
|
27
|
+
readonly requiredExecutionLevel: ExecutionLevel;
|
|
28
|
+
/** Require a fresh human decision for every call, regardless of execution level. */
|
|
29
|
+
readonly alwaysRequiresApproval?: boolean;
|
|
30
|
+
readonly execute: (
|
|
31
|
+
input: unknown,
|
|
32
|
+
ctx: ToolContext,
|
|
33
|
+
) => Promise<unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 一次装配声明的全部 Tool,键即模型可见的工具名。 */
|
|
37
|
+
export type ToolRegistry = Record<string, ToolSpec>;
|
|
38
|
+
|
|
39
|
+
export function emptyToolRegistry(): ToolRegistry {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function mergeToolRegistries(...registries: ToolRegistry[]): ToolRegistry {
|
|
44
|
+
const merged: ToolRegistry = {};
|
|
45
|
+
for (const registry of registries) {
|
|
46
|
+
for (const [name, spec] of Object.entries(registry)) {
|
|
47
|
+
if (name in merged) {
|
|
48
|
+
throw new Error(`Duplicate Runtime Tool: ${name}`);
|
|
49
|
+
}
|
|
50
|
+
merged[name] = spec;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function toolRegistryFromPiCandidates(
|
|
57
|
+
candidates:
|
|
58
|
+
| readonly PiToolCandidate[]
|
|
59
|
+
| Record<string, PiToolCandidate>,
|
|
60
|
+
): ToolRegistry {
|
|
61
|
+
const list = Array.isArray(candidates)
|
|
62
|
+
? candidates
|
|
63
|
+
: Object.values(candidates);
|
|
64
|
+
const registry: ToolRegistry = {};
|
|
65
|
+
for (const candidate of list) {
|
|
66
|
+
const name = candidate.tool.name;
|
|
67
|
+
if (!name.trim()) {
|
|
68
|
+
throw new Error("Pi Tool name must not be empty");
|
|
69
|
+
}
|
|
70
|
+
registry[name] = piCandidateToToolSpec(candidate);
|
|
71
|
+
}
|
|
72
|
+
return registry;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function piCandidateToToolSpec(candidate: PiToolCandidate): ToolSpec {
|
|
76
|
+
const name = candidate.tool.name;
|
|
77
|
+
return {
|
|
78
|
+
label: candidate.tool.label ?? name,
|
|
79
|
+
description: candidate.tool.description,
|
|
80
|
+
parameters: candidate.tool.parameters,
|
|
81
|
+
requiredExecutionLevel: candidate.requiredExecutionLevel,
|
|
82
|
+
...(candidate.alwaysRequiresApproval
|
|
83
|
+
? { alwaysRequiresApproval: true }
|
|
84
|
+
: {}),
|
|
85
|
+
execute: async (input, ctx) => {
|
|
86
|
+
const execute = candidate.tool.execute;
|
|
87
|
+
if (typeof execute !== "function") {
|
|
88
|
+
throw new Error(`Tool "${name}" is not executable`);
|
|
89
|
+
}
|
|
90
|
+
const result = await execute(
|
|
91
|
+
ctx.toolCallId,
|
|
92
|
+
input,
|
|
93
|
+
ctx.signal,
|
|
94
|
+
undefined,
|
|
95
|
+
);
|
|
96
|
+
return result.details ?? result;
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Kernel 绑定仍需要的执行后端;不出现在 Definition 公开类型里。 */
|
|
102
|
+
export interface RuntimeToolBindings {
|
|
103
|
+
readonly workspace?: WorkspacePort;
|
|
104
|
+
readonly memory?: RuntimeMemoryPort;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Worker `tools()` 可返回纯注册表,或附带 Kernel 绑定与降级信息。
|
|
109
|
+
*/
|
|
110
|
+
export interface ToolAssemblyResult {
|
|
111
|
+
readonly tools: ToolRegistry;
|
|
112
|
+
readonly bindings?: RuntimeToolBindings;
|
|
113
|
+
readonly memoryProfile?: import("./kernel/profile").RuntimeMemoryProfile;
|
|
114
|
+
readonly enabledSubagents?: readonly string[];
|
|
115
|
+
readonly degradations?: readonly RuntimeDegradation[];
|
|
116
|
+
readonly surfacePolicy?: ToolSurfaceSelectionPolicy;
|
|
117
|
+
readonly commitGuard?: () => Promise<void>;
|
|
118
|
+
/** 释放本次装配创建的外部资源;临时 Agent 终止后由 Runtime 调用。 */
|
|
119
|
+
readonly dispose?: () => Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function normalizeToolAssembly(
|
|
123
|
+
input: ToolRegistry | ToolAssemblyResult,
|
|
124
|
+
): ToolAssemblyResult {
|
|
125
|
+
if ("tools" in input && typeof input.tools === "object" && input.tools !== null) {
|
|
126
|
+
return input as ToolAssemblyResult;
|
|
127
|
+
}
|
|
128
|
+
return { tools: input as ToolRegistry };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** @deprecated 使用 `ToolSpec`。 */
|
|
132
|
+
export type PlatformToolSpec = ToolSpec;
|
|
133
|
+
|
|
134
|
+
/** @deprecated 使用 `ToolContext`。 */
|
|
135
|
+
export type PlatformToolContext = ToolContext;
|
|
136
|
+
|
|
137
|
+
/** @deprecated 使用 `ToolRegistry`。 */
|
|
138
|
+
export type PlatformToolRegistry = ToolRegistry;
|
|
139
|
+
|
|
140
|
+
/** @deprecated 使用 `emptyToolRegistry`。 */
|
|
141
|
+
export function emptyPlatformToolRegistry(): ToolRegistry {
|
|
142
|
+
return emptyToolRegistry();
|
|
143
|
+
}
|