@springbrand/agent-runtime 0.2.0-alpha.13 → 0.2.0-alpha.15
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/adapter/cloudflare/universal-agent/preparation.ts +2 -2
- package/src/adapter/cloudflare/universal-agent/tools.ts +3 -6
- package/src/index.ts +2 -2
- package/src/kernel/submission-lifecycle.ts +18 -5
- package/src/layers/context/budget/gate.ts +99 -0
- package/src/lib/prompt.ts +4 -3
- package/src/pi/message/projection.ts +2 -2
- package/src/pi/runtime-adapter/assembly.ts +2 -2
- package/src/pi/runtime-adapter/execution.ts +47 -15
- package/src/pi/runtime-adapter/index.ts +1 -0
- package/src/pi/runtime-adapter/models.ts +1 -1
- package/src/pi/runtime-adapter/recovery.ts +17 -17
- package/src/pi/runtime-adapter/transcript.ts +2 -2
- package/src/pi/tool/base.ts +113 -27
- package/src/pi/tool/compiler.ts +66 -6
- package/src/pi/tool/core-host.ts +50 -27
- package/src/pi/tool/core.ts +4 -16
- package/src/pi/tool/skill.ts +78 -3
- package/src/pi/tool/workspace-sandbox.ts +4 -4
- package/src/pi/turn/tool-recovery.ts +7 -7
- package/src/runtime-agent.ts +8 -3
- package/src/runtime-assembler.ts +45 -8
- package/src/runtime.ts +58 -20
- package/src/tool-registry.ts +8 -1
package/src/runtime-agent.ts
CHANGED
|
@@ -652,9 +652,14 @@ export function defineRuntimeAgent<
|
|
|
652
652
|
const policy = assembly.surfacePolicy;
|
|
653
653
|
return {
|
|
654
654
|
...assembly,
|
|
655
|
-
bindings:
|
|
656
|
-
|
|
657
|
-
|
|
655
|
+
bindings: {
|
|
656
|
+
...(assembly.bindings?.workspace
|
|
657
|
+
? { workspace: assembly.bindings.workspace }
|
|
658
|
+
: {}),
|
|
659
|
+
...(assembly.bindings?.codeExecution
|
|
660
|
+
? { codeExecution: assembly.bindings.codeExecution }
|
|
661
|
+
: {}),
|
|
662
|
+
},
|
|
658
663
|
memoryProfile: {
|
|
659
664
|
enabled: false,
|
|
660
665
|
memoryTokens: 2_000,
|
package/src/runtime-assembler.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { SkillSource } from "agents/skills";
|
|
2
2
|
import type {
|
|
3
|
-
RuntimeCodeExecutionPort,
|
|
4
3
|
RuntimeGatewayPort,
|
|
5
4
|
RuntimeMemoryPort,
|
|
6
5
|
RuntimePlatformPort,
|
|
@@ -44,7 +43,11 @@ import type {
|
|
|
44
43
|
RuntimeSkillContribution,
|
|
45
44
|
RuntimeToolSurfacePolicy,
|
|
46
45
|
} from "./runtime-definition";
|
|
47
|
-
import
|
|
46
|
+
import {
|
|
47
|
+
toolRegistryFromPiCandidates,
|
|
48
|
+
type RuntimeCodeExecutionFactory,
|
|
49
|
+
type ToolRegistry,
|
|
50
|
+
} from "./tool-registry";
|
|
48
51
|
import { withRuntimeLoadTimeout } from "./kernel/runtime-load";
|
|
49
52
|
import {
|
|
50
53
|
basePiToolCandidates,
|
|
@@ -52,6 +55,7 @@ import {
|
|
|
52
55
|
} from "./pi/tool/base";
|
|
53
56
|
import {
|
|
54
57
|
browserQuickActionPiToolCandidates,
|
|
58
|
+
codeExecutionPiToolCandidate,
|
|
55
59
|
} from "./pi/tool/core";
|
|
56
60
|
import { skillPiToolCandidates } from "./pi/tool/skill";
|
|
57
61
|
import { createWebSearch } from "./pi/tool/web-search";
|
|
@@ -77,7 +81,7 @@ export interface RuntimeAssemblyInput {
|
|
|
77
81
|
readonly provider: RuntimeProviderPort;
|
|
78
82
|
readonly platform: RuntimePlatformPort;
|
|
79
83
|
readonly workspace?: WorkspacePort;
|
|
80
|
-
readonly codeExecution?:
|
|
84
|
+
readonly codeExecution?: RuntimeCodeExecutionFactory;
|
|
81
85
|
readonly sandbox?: RuntimeSandboxPort;
|
|
82
86
|
readonly memory?: RuntimeMemoryPort;
|
|
83
87
|
readonly hostTools: readonly PiToolCandidate[];
|
|
@@ -150,6 +154,7 @@ function assertMemoryProfile(profile: RuntimeMemoryProfile): void {
|
|
|
150
154
|
}
|
|
151
155
|
|
|
152
156
|
interface ToolSurfaceInput {
|
|
157
|
+
readonly codeExecution?: RuntimeCodeExecutionFactory;
|
|
153
158
|
readonly platform: RuntimePlatformPort;
|
|
154
159
|
readonly workspace?: WorkspacePort;
|
|
155
160
|
readonly memory?: {
|
|
@@ -215,18 +220,46 @@ async function createToolSurface(
|
|
|
215
220
|
...staticCandidates,
|
|
216
221
|
...candidates,
|
|
217
222
|
]) {
|
|
218
|
-
const name = requiredName(candidate.tool.name, "
|
|
223
|
+
const name = requiredName(candidate.tool.name, "SpringBrand Tool");
|
|
219
224
|
if (!visible(candidate)) continue;
|
|
220
225
|
if (!EXECUTION_LEVELS.includes(candidate.requiredExecutionLevel)) {
|
|
221
|
-
throw new Error(`
|
|
226
|
+
throw new Error(`SpringBrand Tool ${name} execution level is invalid`);
|
|
222
227
|
}
|
|
223
228
|
if (tools.has(name)) {
|
|
224
|
-
throw new Error(`Duplicate Runtime
|
|
229
|
+
throw new Error(`Duplicate Runtime SpringBrand Tool: ${name}`);
|
|
225
230
|
}
|
|
226
231
|
tools.set(name, Object.freeze({ ...candidate }));
|
|
227
232
|
}
|
|
228
233
|
|
|
229
|
-
|
|
234
|
+
const finalized = [...tools.values()];
|
|
235
|
+
if (tools.has("execute")) {
|
|
236
|
+
throw new Error("SpringBrand reserved Runtime Tool name: execute");
|
|
237
|
+
}
|
|
238
|
+
if (
|
|
239
|
+
!input.codeExecution ||
|
|
240
|
+
deny.has("execute") ||
|
|
241
|
+
allowsTool?.("execute") === false
|
|
242
|
+
) {
|
|
243
|
+
return Object.freeze(finalized);
|
|
244
|
+
}
|
|
245
|
+
const mergeable = finalized.filter(
|
|
246
|
+
(candidate) =>
|
|
247
|
+
!candidate.interaction &&
|
|
248
|
+
typeof candidate.tool.execute === "function",
|
|
249
|
+
);
|
|
250
|
+
const direct = finalized.filter(
|
|
251
|
+
(candidate) =>
|
|
252
|
+
candidate.interaction ||
|
|
253
|
+
typeof candidate.tool.execute !== "function",
|
|
254
|
+
);
|
|
255
|
+
return Object.freeze([
|
|
256
|
+
Object.freeze(codeExecutionPiToolCandidate(
|
|
257
|
+
input.codeExecution.create(
|
|
258
|
+
toolRegistryFromPiCandidates(mergeable),
|
|
259
|
+
),
|
|
260
|
+
)),
|
|
261
|
+
...direct,
|
|
262
|
+
]);
|
|
230
263
|
},
|
|
231
264
|
}),
|
|
232
265
|
extensions: input.extensions.filter(
|
|
@@ -246,7 +279,7 @@ class RuntimeBuilder {
|
|
|
246
279
|
private platform?: RuntimePlatformPort;
|
|
247
280
|
private gateway?: RuntimeGatewayPort;
|
|
248
281
|
private workspace?: WorkspacePort;
|
|
249
|
-
private codeExecution?:
|
|
282
|
+
private codeExecution?: RuntimeCodeExecutionFactory;
|
|
250
283
|
private sandbox?: RuntimeSandboxPort;
|
|
251
284
|
private schedule?: RuntimeSchedulePort;
|
|
252
285
|
private memoryProfile: RuntimeMemoryProfile = DISABLED_MEMORY;
|
|
@@ -470,6 +503,7 @@ class RuntimeBuilder {
|
|
|
470
503
|
});
|
|
471
504
|
const skillSources = [...this.skillSources.values()];
|
|
472
505
|
const toolSurface = await createToolSurface({
|
|
506
|
+
...(this.codeExecution ? { codeExecution: this.codeExecution } : {}),
|
|
473
507
|
platform: this.platform,
|
|
474
508
|
...(this.workspace ? { workspace: this.workspace } : {}),
|
|
475
509
|
...(this.memoryProfile.enabled && this.memory
|
|
@@ -766,6 +800,9 @@ export async function assembleRuntimeSnapshot<
|
|
|
766
800
|
...(toolAssembly.bindings?.workspace
|
|
767
801
|
? { workspace: toolAssembly.bindings.workspace }
|
|
768
802
|
: {}),
|
|
803
|
+
...(toolAssembly.bindings?.codeExecution
|
|
804
|
+
? { codeExecution: toolAssembly.bindings.codeExecution }
|
|
805
|
+
: {}),
|
|
769
806
|
...(memoryProfile.enabled && toolAssembly.bindings?.memory
|
|
770
807
|
? { memory: toolAssembly.bindings.memory }
|
|
771
808
|
: {}),
|
package/src/runtime.ts
CHANGED
|
@@ -187,6 +187,11 @@ interface ActiveTurn {
|
|
|
187
187
|
agent: PreparedPiTurnAdapter;
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
+
interface PlannedContinuationData {
|
|
191
|
+
readonly submissionId: string;
|
|
192
|
+
readonly requestId: string;
|
|
193
|
+
}
|
|
194
|
+
|
|
190
195
|
// 作用:把任意异常整理成可以持久化或发给客户端的文字。
|
|
191
196
|
// 调用:Turn 执行、恢复和业务投影捕获 `unknown` 异常时调用。
|
|
192
197
|
// 原因:错误边界不能假定抛出值一定是 `Error`。
|
|
@@ -553,7 +558,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
553
558
|
status: "failed" as const,
|
|
554
559
|
error:
|
|
555
560
|
receipt.error ??
|
|
556
|
-
`
|
|
561
|
+
`SpringBrand recovery ended with status ${receipt.status}`,
|
|
557
562
|
};
|
|
558
563
|
} catch (error) {
|
|
559
564
|
if (
|
|
@@ -651,7 +656,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
651
656
|
if (contested && !parked) {
|
|
652
657
|
await closeRuntimeGatewaySession(gatewaySession, "gateway.close.contested");
|
|
653
658
|
throw new Error(
|
|
654
|
-
"Cannot reload Runtime while a revision-pinned
|
|
659
|
+
"Cannot reload Runtime while a revision-pinned SpringBrand Turn is active",
|
|
655
660
|
);
|
|
656
661
|
}
|
|
657
662
|
const repin = parked
|
|
@@ -1186,7 +1191,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
1186
1191
|
private preparedPi(): PreparedPiRuntime {
|
|
1187
1192
|
if (!this.runtimePi) {
|
|
1188
1193
|
throw new Error(
|
|
1189
|
-
"
|
|
1194
|
+
"SpringBrand Runtime must be prepared before starting a Turn",
|
|
1190
1195
|
);
|
|
1191
1196
|
}
|
|
1192
1197
|
return this.runtimePi;
|
|
@@ -1695,7 +1700,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
1695
1700
|
);
|
|
1696
1701
|
const submission = this.readSubmission(submissionId);
|
|
1697
1702
|
if (!submission) {
|
|
1698
|
-
throw new Error(`Unknown
|
|
1703
|
+
throw new Error(`Unknown SpringBrand submission: ${submissionId}`);
|
|
1699
1704
|
}
|
|
1700
1705
|
return submission;
|
|
1701
1706
|
}
|
|
@@ -1890,7 +1895,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
1890
1895
|
): void {
|
|
1891
1896
|
const submission = this.readSubmission(submissionId);
|
|
1892
1897
|
if (!submission) {
|
|
1893
|
-
throw new Error(`Unknown
|
|
1898
|
+
throw new Error(`Unknown SpringBrand submission: ${submissionId}`);
|
|
1894
1899
|
}
|
|
1895
1900
|
const existing = this.db.settlements.find(submissionId, call.toolCallId);
|
|
1896
1901
|
const args = json(call.args);
|
|
@@ -2038,7 +2043,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2038
2043
|
const latest = this.readSubmission(submission.submissionId);
|
|
2039
2044
|
if (!latest) {
|
|
2040
2045
|
throw new Error(
|
|
2041
|
-
`Unknown
|
|
2046
|
+
`Unknown SpringBrand submission: ${submission.submissionId}`,
|
|
2042
2047
|
);
|
|
2043
2048
|
}
|
|
2044
2049
|
if (isTerminalSubmissionStatus(latest.status)) return latest;
|
|
@@ -2101,7 +2106,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2101
2106
|
) {
|
|
2102
2107
|
if (terminal.completedAt == null) {
|
|
2103
2108
|
throw new Error(
|
|
2104
|
-
`Aborted
|
|
2109
|
+
`Aborted SpringBrand submission has no completion time: ${latest.submissionId}`,
|
|
2105
2110
|
);
|
|
2106
2111
|
}
|
|
2107
2112
|
this.transcript.appendTurnAbortedMarker(
|
|
@@ -2224,7 +2229,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2224
2229
|
}
|
|
2225
2230
|
}
|
|
2226
2231
|
}
|
|
2227
|
-
throw new Error("
|
|
2232
|
+
throw new Error("SpringBrand recovery plan did not converge");
|
|
2228
2233
|
}
|
|
2229
2234
|
|
|
2230
2235
|
// #endregion
|
|
@@ -2253,7 +2258,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2253
2258
|
typeof userMessage.timestamp !== "number" ||
|
|
2254
2259
|
!submission.userMessageId
|
|
2255
2260
|
) {
|
|
2256
|
-
throw new Error("Queued
|
|
2261
|
+
throw new Error("Queued SpringBrand user message is invalid");
|
|
2257
2262
|
}
|
|
2258
2263
|
const uiMessage = submission.queuedUiMessageJson
|
|
2259
2264
|
? JSON.parse(submission.queuedUiMessageJson) as UIMessage & {
|
|
@@ -2282,7 +2287,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2282
2287
|
if (!latest || latest.status !== "pending") {
|
|
2283
2288
|
if (!latest) {
|
|
2284
2289
|
throw new Error(
|
|
2285
|
-
`Unknown
|
|
2290
|
+
`Unknown SpringBrand submission: ${submission.submissionId}`,
|
|
2286
2291
|
);
|
|
2287
2292
|
}
|
|
2288
2293
|
return latest;
|
|
@@ -2290,7 +2295,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2290
2295
|
const running = this.db.submissions.findRunning();
|
|
2291
2296
|
if (running) {
|
|
2292
2297
|
throw new Error(
|
|
2293
|
-
`
|
|
2298
|
+
`SpringBrand submission ${running.submissionId} is already running`,
|
|
2294
2299
|
);
|
|
2295
2300
|
}
|
|
2296
2301
|
if (submission.regenerateMessageId) {
|
|
@@ -2307,7 +2312,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2307
2312
|
);
|
|
2308
2313
|
if (!appended) {
|
|
2309
2314
|
throw new Error(
|
|
2310
|
-
`
|
|
2315
|
+
`SpringBrand Session message ${submission.userMessageId} already exists`,
|
|
2311
2316
|
);
|
|
2312
2317
|
}
|
|
2313
2318
|
}
|
|
@@ -2317,7 +2322,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2317
2322
|
["pending"],
|
|
2318
2323
|
)) {
|
|
2319
2324
|
throw new Error(
|
|
2320
|
-
`
|
|
2325
|
+
`SpringBrand submission ${submission.submissionId} could not activate`,
|
|
2321
2326
|
);
|
|
2322
2327
|
}
|
|
2323
2328
|
this.db.submissions.clearQueuedPayload(
|
|
@@ -2342,7 +2347,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2342
2347
|
): Promise<StoredSubmission> {
|
|
2343
2348
|
const submission = this.readSubmission(submissionId);
|
|
2344
2349
|
if (!submission) {
|
|
2345
|
-
throw new Error(`Unknown
|
|
2350
|
+
throw new Error(`Unknown SpringBrand submission: ${submissionId}`);
|
|
2346
2351
|
}
|
|
2347
2352
|
if (isTerminalSubmissionStatus(submission.status)) {
|
|
2348
2353
|
return submission;
|
|
@@ -2385,7 +2390,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2385
2390
|
this.sendChatTerminal(
|
|
2386
2391
|
submission.requestId,
|
|
2387
2392
|
failed.status === "error"
|
|
2388
|
-
? failed.error ?? "
|
|
2393
|
+
? failed.error ?? "SpringBrand turn failed"
|
|
2389
2394
|
: undefined,
|
|
2390
2395
|
recovery,
|
|
2391
2396
|
);
|
|
@@ -2455,7 +2460,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2455
2460
|
|
|
2456
2461
|
const ready = this.readSubmission(submissionId);
|
|
2457
2462
|
if (!ready) {
|
|
2458
|
-
throw new Error(`Unknown
|
|
2463
|
+
throw new Error(`Unknown SpringBrand submission: ${submissionId}`);
|
|
2459
2464
|
}
|
|
2460
2465
|
if (isTerminalSubmissionStatus(ready.status)) return ready;
|
|
2461
2466
|
if (ready.abortReason) {
|
|
@@ -2517,6 +2522,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2517
2522
|
agent: adapter,
|
|
2518
2523
|
};
|
|
2519
2524
|
let streamId: string | undefined;
|
|
2525
|
+
let runResult: import("./pi/runtime-adapter").PiTurnRunResult | undefined;
|
|
2520
2526
|
|
|
2521
2527
|
const deactivate = this.submissions.activate(submission, turn);
|
|
2522
2528
|
await this.broadcastApprovals();
|
|
@@ -2536,7 +2542,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2536
2542
|
streamId = activeStreamId;
|
|
2537
2543
|
this.streamBySubmission.set(submissionId, streamId);
|
|
2538
2544
|
try {
|
|
2539
|
-
await adapter.run({});
|
|
2545
|
+
runResult = await adapter.run({});
|
|
2540
2546
|
} finally {
|
|
2541
2547
|
this.streamBySubmission.delete(submissionId);
|
|
2542
2548
|
}
|
|
@@ -2548,10 +2554,27 @@ export abstract class AgentRuntimeKernel<
|
|
|
2548
2554
|
if (streamId) this.failRecoverableStream(streamId);
|
|
2549
2555
|
return this.readSubmission(submissionId)!;
|
|
2550
2556
|
}
|
|
2557
|
+
if (runResult?.kind === "yielded") {
|
|
2558
|
+
const latest = this.readSubmission(submissionId)!;
|
|
2559
|
+
if (latest.abortReason) {
|
|
2560
|
+
return this.submissions.finish(
|
|
2561
|
+
latest,
|
|
2562
|
+
"aborted",
|
|
2563
|
+
latest.abortReason,
|
|
2564
|
+
);
|
|
2565
|
+
}
|
|
2566
|
+
await this.schedule(
|
|
2567
|
+
0,
|
|
2568
|
+
"_piPlannedContinuation",
|
|
2569
|
+
{ submissionId, requestId: submission.requestId },
|
|
2570
|
+
{ idempotent: true },
|
|
2571
|
+
);
|
|
2572
|
+
return latest;
|
|
2573
|
+
}
|
|
2551
2574
|
const intent = terminalIntent ?? {
|
|
2552
2575
|
outcome: "failed" as const,
|
|
2553
2576
|
message:
|
|
2554
|
-
"
|
|
2577
|
+
"SpringBrand turn ended without an authoritative assistant message",
|
|
2555
2578
|
};
|
|
2556
2579
|
const terminal = await this.submissions.finish(
|
|
2557
2580
|
submission,
|
|
@@ -2713,7 +2736,7 @@ export abstract class AgentRuntimeKernel<
|
|
|
2713
2736
|
this.sendChatTerminal(
|
|
2714
2737
|
turn.requestId,
|
|
2715
2738
|
submission.status === "error"
|
|
2716
|
-
? submission.error ?? "
|
|
2739
|
+
? submission.error ?? "SpringBrand turn failed"
|
|
2717
2740
|
: undefined,
|
|
2718
2741
|
turn.continuation,
|
|
2719
2742
|
);
|
|
@@ -3562,9 +3585,9 @@ export abstract class AgentRuntimeKernel<
|
|
|
3562
3585
|
const adapter = this.createSubmissionExecutionAdapter(submission);
|
|
3563
3586
|
const spec = adapter.interactionSpec(pending.toolName);
|
|
3564
3587
|
if (!spec) return { ok: false };
|
|
3565
|
-
if (!spec.validateResponse(response)) return { ok: false };
|
|
3566
3588
|
|
|
3567
3589
|
const input = safeParseJson(pending.inputJson);
|
|
3590
|
+
if (!spec.validateResponse(input, response)) return { ok: false };
|
|
3568
3591
|
const settled = spec.settle
|
|
3569
3592
|
? spec.settle(input, response)
|
|
3570
3593
|
: defaultInteractionResult(response);
|
|
@@ -3687,6 +3710,21 @@ export abstract class AgentRuntimeKernel<
|
|
|
3687
3710
|
}
|
|
3688
3711
|
}
|
|
3689
3712
|
|
|
3713
|
+
async _piPlannedContinuation(
|
|
3714
|
+
data?: PlannedContinuationData,
|
|
3715
|
+
): Promise<void> {
|
|
3716
|
+
if (!data?.submissionId || !data.requestId) return;
|
|
3717
|
+
const submission = this.readSubmission(data.submissionId);
|
|
3718
|
+
if (
|
|
3719
|
+
!submission ||
|
|
3720
|
+
submission.requestId !== data.requestId ||
|
|
3721
|
+
isTerminalSubmissionStatus(submission.status)
|
|
3722
|
+
) {
|
|
3723
|
+
return;
|
|
3724
|
+
}
|
|
3725
|
+
await this.submissions.recoverAfterCurrent(submission.submissionId);
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3690
3728
|
// 作用:Agent Tool 子运行开始后重算一次活动投影。
|
|
3691
3729
|
// 调用:Agents SDK 在登记子运行后调用。
|
|
3692
3730
|
// 原因:分离的子运行不进 Submission 表,不在这里重算,Host 的列表会显示成已经空闲。
|
package/src/tool-registry.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ExecutionLevel } from "./lib/execution-level";
|
|
2
2
|
import type {
|
|
3
|
+
RuntimeCodeExecutionPort,
|
|
3
4
|
RuntimeMemoryPort,
|
|
4
5
|
RuntimeSubagentPort,
|
|
5
6
|
WorkspacePort,
|
|
@@ -37,6 +38,11 @@ export interface ToolSpec {
|
|
|
37
38
|
/** 一次装配声明的全部 Tool,键即模型可见的工具名。 */
|
|
38
39
|
export type ToolRegistry = Record<string, ToolSpec>;
|
|
39
40
|
|
|
41
|
+
/** 延迟到最终 Tool Surface 完成后再创建 Code Mode 执行能力。 */
|
|
42
|
+
export interface RuntimeCodeExecutionFactory {
|
|
43
|
+
create(tools: ToolRegistry): RuntimeCodeExecutionPort;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
export function emptyToolRegistry(): ToolRegistry {
|
|
41
47
|
return {};
|
|
42
48
|
}
|
|
@@ -66,7 +72,7 @@ export function toolRegistryFromPiCandidates(
|
|
|
66
72
|
for (const candidate of list) {
|
|
67
73
|
const name = candidate.tool.name;
|
|
68
74
|
if (!name.trim()) {
|
|
69
|
-
throw new Error("
|
|
75
|
+
throw new Error("SpringBrand Tool name must not be empty");
|
|
70
76
|
}
|
|
71
77
|
registry[name] = piCandidateToToolSpec(candidate);
|
|
72
78
|
}
|
|
@@ -102,6 +108,7 @@ export function piCandidateToToolSpec(candidate: PiToolCandidate): ToolSpec {
|
|
|
102
108
|
/** Kernel 绑定仍需要的执行后端;不出现在 Definition 公开类型里。 */
|
|
103
109
|
export interface RuntimeToolBindings {
|
|
104
110
|
readonly workspace?: WorkspacePort;
|
|
111
|
+
readonly codeExecution?: RuntimeCodeExecutionFactory;
|
|
105
112
|
readonly memory?: RuntimeMemoryPort;
|
|
106
113
|
readonly subagents?: RuntimeSubagentPort;
|
|
107
114
|
}
|