@springbrand/agent-runtime 0.1.3-alpha.1 → 0.1.3-alpha.11
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 +12 -3
- package/src/adapter/cloudflare/index.ts +56 -0
- package/src/adapter/cloudflare/resources/runtime-resources.ts +89 -0
- package/src/adapter/cloudflare/sandbox/adapter.ts +1513 -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 +254 -0
- package/src/adapter/cloudflare/universal-agent/hooks.ts +35 -0
- package/src/adapter/cloudflare/universal-agent/preparation.ts +277 -0
- package/src/adapter/cloudflare/universal-agent/tools.ts +80 -0
- package/src/adapter/cloudflare/workspace/git-fs.ts +178 -0
- package/src/adapter/cloudflare/workspace/publisher.ts +31 -0
- package/src/adapter/cloudflare/workspace/scoped-workspace.ts +376 -0
- package/src/adapter/cloudflare/workspace/version-control.ts +374 -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 +25 -1
- package/src/db/submission.repo.ts +63 -1
- package/src/index.ts +57 -21
- package/src/kernel/approval-lifecycle.ts +41 -6
- package/src/kernel/bindings.ts +73 -9
- package/src/kernel/interaction-lifecycle.ts +395 -0
- package/src/kernel/public-contracts.ts +2 -0
- package/src/kernel/recoverable-chat-agent.ts +104 -6
- 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 +191 -0
- package/src/kernel/state.ts +12 -1
- package/src/kernel/submission-lifecycle.ts +33 -2
- package/src/layers/orchestration/temporary-agent/core.ts +12 -1
- package/src/layers/orchestration/temporary-agent/runner.ts +1 -2
- package/src/lib/mcp.ts +7 -3
- package/src/lib/prompt.ts +4 -1
- package/src/lib/telemetry-dev.ts +7 -4
- package/src/pi/assembly/context.ts +3 -3
- package/src/pi/assembly/extensions.ts +11 -22
- package/src/pi/assembly/snapshot.ts +6 -3
- package/src/pi/message/contract.ts +7 -0
- package/src/pi/message/conversion.ts +9 -1
- package/src/pi/runtime-adapter/assembly.ts +26 -31
- package/src/pi/runtime-adapter/execution.ts +198 -15
- package/src/pi/runtime-adapter/index.ts +24 -8
- package/src/pi/runtime-adapter/models.ts +382 -35
- package/src/pi/runtime-adapter/recovery.ts +188 -1
- package/src/pi/runtime-adapter/transcript.ts +61 -3
- package/src/pi/tool/ai-adapter.ts +58 -1
- package/src/pi/tool/base.ts +190 -12
- package/src/pi/tool/compiler.ts +34 -1
- package/src/pi/tool/core-host.ts +19 -24
- package/src/pi/tool/core.ts +30 -120
- package/src/pi/tool/gateway.ts +54 -0
- package/src/pi/tool/index.ts +2 -0
- package/src/pi/tool/mcp.ts +96 -68
- package/src/pi/tool/schedule.ts +41 -19
- package/src/pi/tool/skill.ts +126 -420
- package/src/pi/tool/subagent.ts +14 -2
- package/src/pi/tool/web-fetch.ts +281 -0
- package/src/pi/tool/web-search/api.ts +34 -18
- package/src/pi/tool/web-search/web-search.ts +0 -1
- package/src/pi/tool/workspace-revision.ts +64 -0
- package/src/pi/tool/workspace-sandbox.ts +105 -263
- 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 +568 -321
- package/src/{plugins.ts → runtime-assembler.ts} +372 -398
- package/src/runtime-definition.ts +175 -0
- package/src/runtime.ts +835 -204
- package/src/tool-registry.ts +143 -0
- package/src/workspace-versioning.ts +46 -0
package/src/runtime-agent.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callable,
|
|
3
3
|
type Agent,
|
|
4
|
-
type
|
|
4
|
+
type AgentToolChildAdapter,
|
|
5
5
|
type ChatCapableAgentClass,
|
|
6
|
-
type RunAgentToolOptions,
|
|
7
6
|
} from "agents";
|
|
8
7
|
import type { UIMessage } from "ai";
|
|
9
8
|
import type { PiCanonicalTranscriptSnapshot } from "./pi/runtime-adapter";
|
|
@@ -14,20 +13,52 @@ import type {
|
|
|
14
13
|
MessageDispatchReceipt,
|
|
15
14
|
SubmissionReceipt,
|
|
16
15
|
} from "./kernel/receipts";
|
|
17
|
-
import type { ExecutionLevel } from "./lib/execution-level";
|
|
18
16
|
import type { RuntimeState } from "./kernel/state";
|
|
19
17
|
import type {
|
|
20
18
|
TemporaryAgentApprovalDecision,
|
|
21
19
|
TemporaryAgentApprovalRequest,
|
|
22
|
-
|
|
23
|
-
TemporaryAgentRequest,
|
|
24
|
-
TemporaryAgentRunContext,
|
|
20
|
+
TemporaryAgentLaunch,
|
|
25
21
|
} from "./layers/orchestration/temporary-agent/core";
|
|
26
|
-
import
|
|
27
|
-
import {
|
|
22
|
+
import { TEMPORARY_AGENT_LAUNCH_KEY } from "./layers/orchestration/temporary-agent/core";
|
|
23
|
+
import {
|
|
24
|
+
temporaryAgentExtensionIsSafe,
|
|
25
|
+
temporaryAgentToolAllowed,
|
|
26
|
+
} from "./layers/orchestration/temporary-agent/runner";
|
|
27
|
+
import {
|
|
28
|
+
EXECUTION_LEVELS,
|
|
29
|
+
requiresExecutionApproval,
|
|
30
|
+
type ExecutionLevel,
|
|
31
|
+
} from "./lib/execution-level";
|
|
32
|
+
import {
|
|
33
|
+
assembleRuntimeSnapshot,
|
|
34
|
+
type RuntimeCandidate,
|
|
35
|
+
} from "./runtime-assembler";
|
|
36
|
+
import type {
|
|
37
|
+
ResolvedResources,
|
|
38
|
+
RuntimeAgentHooks,
|
|
39
|
+
} from "./runtime-definition";
|
|
40
|
+
import {
|
|
41
|
+
normalizeToolAssembly,
|
|
42
|
+
type ToolAssemblyResult,
|
|
43
|
+
type ToolRegistry,
|
|
44
|
+
} from "./tool-registry";
|
|
45
|
+
import type { RuntimeAssemblyView } from "./kernel/runtime-assembly-view";
|
|
46
|
+
import type { RuntimeConfigUpdateResult } from "./kernel/runtime-config";
|
|
47
|
+
import {
|
|
48
|
+
logRuntimeLoadFailure,
|
|
49
|
+
RUNTIME_LOAD_TIMEOUT_MS,
|
|
50
|
+
withRuntimeLoadTimeout,
|
|
51
|
+
} from "./kernel/runtime-load";
|
|
52
|
+
import { AgentToolRuntimeKernel } from "./agent-tool-runtime";
|
|
53
|
+
import type {
|
|
54
|
+
RuntimeAgentConfigContext,
|
|
55
|
+
RuntimeAgentPlanningContext,
|
|
56
|
+
RuntimeAgentRole,
|
|
57
|
+
RuntimeAgentToolResult,
|
|
58
|
+
} from "./runtime-agent-context";
|
|
28
59
|
|
|
29
60
|
/**
|
|
30
|
-
* 本文件把应用提供的
|
|
61
|
+
* 本文件把应用提供的 Config Definition 与 Planner 接到 Cloudflare Agent 生命周期。
|
|
31
62
|
*
|
|
32
63
|
* @remarks
|
|
33
64
|
* 核心术语见包入口 `index.ts`。
|
|
@@ -35,201 +66,81 @@ import { AgentRuntimeKernel } from "./runtime";
|
|
|
35
66
|
|
|
36
67
|
// #region Agent 身份与公开契约
|
|
37
68
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"eval",
|
|
54
|
-
"export",
|
|
55
|
-
"extends",
|
|
56
|
-
"false",
|
|
57
|
-
"finally",
|
|
58
|
-
"for",
|
|
59
|
-
"function",
|
|
60
|
-
"if",
|
|
61
|
-
"implements",
|
|
62
|
-
"import",
|
|
63
|
-
"in",
|
|
64
|
-
"instanceof",
|
|
65
|
-
"interface",
|
|
66
|
-
"let",
|
|
67
|
-
"new",
|
|
68
|
-
"null",
|
|
69
|
-
"package",
|
|
70
|
-
"private",
|
|
71
|
-
"protected",
|
|
72
|
-
"public",
|
|
73
|
-
"return",
|
|
74
|
-
"static",
|
|
75
|
-
"super",
|
|
76
|
-
"switch",
|
|
77
|
-
"this",
|
|
78
|
-
"throw",
|
|
79
|
-
"true",
|
|
80
|
-
"try",
|
|
81
|
-
"typeof",
|
|
82
|
-
"var",
|
|
83
|
-
"void",
|
|
84
|
-
"while",
|
|
85
|
-
"with",
|
|
86
|
-
"yield",
|
|
87
|
-
]);
|
|
88
|
-
const JAVASCRIPT_IDENTIFIER =
|
|
89
|
-
/^[$_\p{ID_Start}][$\u200C\u200D\p{ID_Continue}]*$/u;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* 描述 Agent 寻址路径中的一级父子节点。
|
|
93
|
-
*
|
|
94
|
-
* @remarks
|
|
95
|
-
* Cloudflare Agents SDK 用 `parentPath` 暴露根节点到直接父节点的路径。
|
|
96
|
-
*
|
|
97
|
-
* 调用方通常只读取,不应自行构造后写回 SDK。
|
|
98
|
-
*/
|
|
99
|
-
export interface RuntimeAgentPathStep {
|
|
100
|
-
className: string;
|
|
101
|
-
name: string;
|
|
69
|
+
export type {
|
|
70
|
+
RuntimeAgentConfigContext,
|
|
71
|
+
RuntimeAgentContext,
|
|
72
|
+
RuntimeAgentPathStep,
|
|
73
|
+
RuntimeAgentPlanningContext,
|
|
74
|
+
RuntimeAgentRole,
|
|
75
|
+
RuntimeAgentToolResult,
|
|
76
|
+
RuntimeAssemblyContext,
|
|
77
|
+
} from "./runtime-agent-context";
|
|
78
|
+
|
|
79
|
+
/** Host 一次性准备的完整 Runtime 加载结果。 */
|
|
80
|
+
export interface LoadedRuntime<Config> {
|
|
81
|
+
readonly runtimeKey: string;
|
|
82
|
+
readonly config: Config;
|
|
83
|
+
readonly resources: ResolvedResources;
|
|
102
84
|
}
|
|
103
85
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
* @remarks
|
|
108
|
-
* Subagent 端口在调用 `RuntimeAgentConfigContext.runAgentTool` 后读取它。
|
|
109
|
-
*
|
|
110
|
-
* 这里只保留 Runtime 需要的结果,避免把 SDK 内部运行对象暴露给应用。
|
|
111
|
-
*/
|
|
112
|
-
export interface RuntimeAgentToolResult {
|
|
113
|
-
status: string;
|
|
114
|
-
runId: string;
|
|
115
|
-
output?: unknown;
|
|
116
|
-
summary?: string;
|
|
117
|
-
error?: string;
|
|
86
|
+
export interface RuntimeConfigUpdate<Change> {
|
|
87
|
+
readonly changed: boolean;
|
|
88
|
+
readonly change: Change;
|
|
118
89
|
}
|
|
119
90
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
* 待确认:原注释把 getter 的必要性归因于 facet 元数据在 Durable Object
|
|
126
|
-
* 构造后恢复,但当前 SDK 会在用户 `onStart` 前完成恢复。
|
|
127
|
-
*/
|
|
128
|
-
export interface RuntimeAgentConfigContext<
|
|
129
|
-
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
91
|
+
interface RuntimeAgentDefinitionBase<
|
|
92
|
+
Env extends Cloudflare.Env,
|
|
93
|
+
Config,
|
|
94
|
+
Command,
|
|
95
|
+
Change,
|
|
130
96
|
> {
|
|
131
|
-
/**
|
|
132
|
-
readonly ctx: DurableObjectState;
|
|
133
|
-
/** 读取当前 Worker 的环境绑定。 */
|
|
134
|
-
readonly env: Env;
|
|
135
|
-
/** 读取当前 Agent 实例名称。 */
|
|
97
|
+
/** 必须等于 Worker 导出名(Wrangler `class_name`)。 */
|
|
136
98
|
readonly name: string;
|
|
137
|
-
|
|
138
|
-
readonly
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
* 给「运行中改变自身可用能力」的 Tool 使用:先把变更写进持久层,再调用它,
|
|
153
|
-
* 新的 Snapshot 会按同一条解析链重新装配。不要在 Plugin 的 loader 里调用,
|
|
154
|
-
* 那会让装配递归。
|
|
155
|
-
*/
|
|
156
|
-
reloadRuntime(): Promise<void>;
|
|
157
|
-
/**
|
|
158
|
-
* 通过当前 Agent 调用一个受 SDK 管理的子 Agent Tool。
|
|
159
|
-
*
|
|
160
|
-
* @remarks
|
|
161
|
-
* subagent 端口在父 Agent 需要保留子运行状态、事件和取消边界时调用。
|
|
162
|
-
*
|
|
163
|
-
* 调用必须经过当前 Agent 实例,才能使用 Cloudflare Agents SDK 的受管子运行登记。
|
|
164
|
-
*/
|
|
165
|
-
runAgentTool(
|
|
166
|
-
agentClass: ChatCapableAgentClass,
|
|
167
|
-
options: RunAgentToolOptions<unknown>,
|
|
168
|
-
): Promise<RuntimeAgentToolResult>;
|
|
169
|
-
/**
|
|
170
|
-
* 清理符合年龄和状态条件的 SDK 子运行记录。
|
|
171
|
-
*
|
|
172
|
-
* @remarks
|
|
173
|
-
* subagent 清理逻辑在需要回收已保留运行时调用。
|
|
174
|
-
*
|
|
175
|
-
* 必须显式提供年龄和状态筛选,避免无边界地删除仍需查询的子运行。
|
|
176
|
-
*/
|
|
177
|
-
clearAgentToolRuns(options: {
|
|
178
|
-
olderThan: number;
|
|
179
|
-
status: AgentToolRunStatus[];
|
|
180
|
-
}): Promise<void>;
|
|
181
|
-
/** 读取当前已装配 User Agent 的执行档位。 */
|
|
182
|
-
executionLevel(): ExecutionLevel;
|
|
183
|
-
/**
|
|
184
|
-
* 在当前 Session Runtime 中执行一个仅对本次调用存活的临时 Agent。
|
|
185
|
-
*
|
|
186
|
-
* @remarks
|
|
187
|
-
* temporary-agent 端口在 Tool 需要一次性委派时调用。
|
|
188
|
-
*
|
|
189
|
-
* 它复用当前 Session 的 Runtime 和取消信号,但不创建持久 facet。
|
|
190
|
-
*/
|
|
191
|
-
runTemporaryAgent(
|
|
192
|
-
request: TemporaryAgentRequest,
|
|
193
|
-
context: TemporaryAgentRunContext,
|
|
194
|
-
execute: TemporaryAgentExecutor,
|
|
195
|
-
): Promise<string>;
|
|
99
|
+
|
|
100
|
+
readonly load: (
|
|
101
|
+
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
102
|
+
requestedRuntimeKey?: string,
|
|
103
|
+
) => Promise<LoadedRuntime<Config>>;
|
|
104
|
+
|
|
105
|
+
readonly tools: (
|
|
106
|
+
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
107
|
+
config: Config,
|
|
108
|
+
) => ToolRegistry | ToolAssemblyResult | Promise<ToolRegistry | ToolAssemblyResult>;
|
|
109
|
+
|
|
110
|
+
readonly hooks?:
|
|
111
|
+
| RuntimeAgentHooks<Env, Config, Command, Change>
|
|
112
|
+
| ((context: RuntimeAgentPlanningContext<Env, Command, Change>) =>
|
|
113
|
+
RuntimeAgentHooks<Env, Config, Command, Change>);
|
|
196
114
|
}
|
|
197
115
|
|
|
198
|
-
|
|
199
|
-
* 告诉 Runtime 如何定义 Agent 类并创建配置。
|
|
200
|
-
*
|
|
201
|
-
* @remarks
|
|
202
|
-
* Worker 入口把它传给 `defineRuntimeAgent`。
|
|
203
|
-
*
|
|
204
|
-
* `createConfig` 只负责业务寻址和 Plugin 创建,原子装配由 Runtime 完成。
|
|
205
|
-
*/
|
|
206
|
-
export interface RuntimeAgentDefinition<
|
|
116
|
+
export interface ReadonlyRuntimeAgentDefinition<
|
|
207
117
|
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
* 为当前 Agent 实例创建一次完整的 Plugin 配置。
|
|
221
|
-
*
|
|
222
|
-
* @remarks
|
|
223
|
-
* 生成类在首次执行需求和显式切换 Runtime key 时调用。
|
|
224
|
-
*
|
|
225
|
-
* 返回值尚未生效,只有 Runtime 完成校验和提交后才会替换当前 Snapshot。
|
|
226
|
-
*/
|
|
227
|
-
createConfig(
|
|
118
|
+
Config = unknown,
|
|
119
|
+
> extends RuntimeAgentDefinitionBase<Env, Config, never, never> {
|
|
120
|
+
readonly update?: never;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface MutableRuntimeAgentDefinition<
|
|
124
|
+
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
125
|
+
Config = unknown,
|
|
126
|
+
Command = unknown,
|
|
127
|
+
Change = unknown,
|
|
128
|
+
> extends RuntimeAgentDefinitionBase<Env, Config, Command, Change> {
|
|
129
|
+
readonly update: (
|
|
228
130
|
context: RuntimeAgentConfigContext<Env>,
|
|
229
|
-
|
|
230
|
-
)
|
|
131
|
+
command: Command,
|
|
132
|
+
) => Promise<RuntimeConfigUpdate<Change>>;
|
|
231
133
|
}
|
|
232
134
|
|
|
135
|
+
export type RuntimeAgentDefinition<
|
|
136
|
+
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
137
|
+
Config = unknown,
|
|
138
|
+
Command = never,
|
|
139
|
+
Change = never,
|
|
140
|
+
> = [Command] extends [never]
|
|
141
|
+
? ReadonlyRuntimeAgentDefinition<Env, Config>
|
|
142
|
+
: MutableRuntimeAgentDefinition<Env, Config, Command, Change>;
|
|
143
|
+
|
|
233
144
|
/**
|
|
234
145
|
* 这是生成 Runtime Agent 的稳定公开控制面。
|
|
235
146
|
*
|
|
@@ -257,6 +168,14 @@ export interface RuntimeAgentControls {
|
|
|
257
168
|
* 待确认:当前 `refreshContext` 只检查 Snapshot 已安装,没有重新读取 Context 或刷新缓存。
|
|
258
169
|
*/
|
|
259
170
|
refreshMemoryContext(): Promise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Read the Runtime Snapshot currently installed on this Session facet.
|
|
173
|
+
*
|
|
174
|
+
* @remarks
|
|
175
|
+
* Debug panels and Host tooling call this to inspect skills, subagents,
|
|
176
|
+
* extensions, and degradations that were actually assembled.
|
|
177
|
+
*/
|
|
178
|
+
getRuntimeAssembly(): Promise<RuntimeAssemblyView>;
|
|
260
179
|
/**
|
|
261
180
|
* 读取 canonical transcript 的浏览器投影。
|
|
262
181
|
*
|
|
@@ -286,6 +205,16 @@ export interface RuntimeAgentControls {
|
|
|
286
205
|
executionId: string,
|
|
287
206
|
decision: ApprovalDecision,
|
|
288
207
|
): Promise<{ ok: boolean }>;
|
|
208
|
+
/**
|
|
209
|
+
* 把客户端投递的响应作为某次 Tool 调用的结果并续跑原 Turn。
|
|
210
|
+
*
|
|
211
|
+
* @remarks
|
|
212
|
+
* 前端经 WS RPC 调用,只带 `toolCallId`。查无、已结算或响应体不过校验都返回 `{ ok: false }`。
|
|
213
|
+
*/
|
|
214
|
+
respondToolInteraction(
|
|
215
|
+
toolCallId: string,
|
|
216
|
+
response: unknown,
|
|
217
|
+
): Promise<{ ok: boolean }>;
|
|
289
218
|
/**
|
|
290
219
|
* 登记一条受管临时 Agent 发起的审批请求。
|
|
291
220
|
*
|
|
@@ -375,6 +304,12 @@ export interface RuntimeAgentControls {
|
|
|
375
304
|
): Promise<{ ok: boolean }>;
|
|
376
305
|
}
|
|
377
306
|
|
|
307
|
+
export interface RuntimeAgentConfigControls<Command, Change> {
|
|
308
|
+
updateConfig(
|
|
309
|
+
command: Command,
|
|
310
|
+
): Promise<RuntimeConfigUpdateResult<Change>>;
|
|
311
|
+
}
|
|
312
|
+
|
|
378
313
|
/**
|
|
379
314
|
* 表示 `defineRuntimeAgent` 生成类的实例。
|
|
380
315
|
*
|
|
@@ -383,7 +318,10 @@ export interface RuntimeAgentControls {
|
|
|
383
318
|
*/
|
|
384
319
|
export type RuntimeAgentInstance<
|
|
385
320
|
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
386
|
-
|
|
321
|
+
Command = never,
|
|
322
|
+
Change = never,
|
|
323
|
+
> = Agent<Env, RuntimeState> & RuntimeAgentControls &
|
|
324
|
+
RuntimeAgentConfigControls<Command, Change> & AgentToolChildAdapter<unknown, string>;
|
|
387
325
|
|
|
388
326
|
/**
|
|
389
327
|
* 表示 `defineRuntimeAgent` 返回的 Durable Object 类构造器。
|
|
@@ -393,26 +331,58 @@ export type RuntimeAgentInstance<
|
|
|
393
331
|
*/
|
|
394
332
|
export interface RuntimeAgentClass<
|
|
395
333
|
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
334
|
+
Command = never,
|
|
335
|
+
Change = never,
|
|
396
336
|
> {
|
|
397
|
-
new (
|
|
337
|
+
new (
|
|
338
|
+
ctx: DurableObjectState,
|
|
339
|
+
env: Env,
|
|
340
|
+
): RuntimeAgentInstance<Env, Command, Change>;
|
|
398
341
|
}
|
|
399
342
|
|
|
400
343
|
// #endregion
|
|
401
344
|
|
|
402
345
|
// #region 生成类的构造与生命周期
|
|
403
346
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
347
|
+
const TERMINAL_AGENT_TOOL_STATUSES = [
|
|
348
|
+
"completed",
|
|
349
|
+
"error",
|
|
350
|
+
"aborted",
|
|
351
|
+
"interrupted",
|
|
352
|
+
] as const;
|
|
353
|
+
const AGENT_TOOL_RETENTION_MS = 24 * 60 * 60 * 1_000;
|
|
354
|
+
|
|
355
|
+
function parseTemporaryAgentLaunch<Config>(
|
|
356
|
+
input: unknown,
|
|
357
|
+
): TemporaryAgentLaunch<Config> {
|
|
358
|
+
const record = input != null && typeof input === "object"
|
|
359
|
+
? input as Record<string, unknown>
|
|
360
|
+
: {};
|
|
361
|
+
const read = (name: string, max: number) => {
|
|
362
|
+
const value = record[name];
|
|
363
|
+
if (typeof value !== "string" || !value.trim() || value.length > max) {
|
|
364
|
+
throw new Error(`invalid temporary agent ${name}`);
|
|
365
|
+
}
|
|
366
|
+
return value.trim();
|
|
367
|
+
};
|
|
368
|
+
const executionLevel = record.executionLevel;
|
|
408
369
|
if (
|
|
409
|
-
|
|
410
|
-
|
|
370
|
+
typeof executionLevel !== "string" ||
|
|
371
|
+
!EXECUTION_LEVELS.includes(executionLevel as ExecutionLevel)
|
|
411
372
|
) {
|
|
412
|
-
throw new Error(
|
|
413
|
-
`Invalid Runtime Agent className "${className}": expected a non-reserved JavaScript identifier`,
|
|
414
|
-
);
|
|
373
|
+
throw new Error("invalid temporary agent executionLevel");
|
|
415
374
|
}
|
|
375
|
+
if (!("config" in record)) {
|
|
376
|
+
throw new Error("invalid temporary agent config");
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
subagentName: read("subagentName", 128),
|
|
380
|
+
instructions: read("instructions", 65_536),
|
|
381
|
+
task: read("task", 65_536),
|
|
382
|
+
runtimeKey: read("runtimeKey", 512),
|
|
383
|
+
config: record.config as Config,
|
|
384
|
+
executionLevel: executionLevel as ExecutionLevel,
|
|
385
|
+
};
|
|
416
386
|
}
|
|
417
387
|
|
|
418
388
|
/**
|
|
@@ -425,20 +395,44 @@ function assertClassName(className: string): void {
|
|
|
425
395
|
*/
|
|
426
396
|
export function defineRuntimeAgent<
|
|
427
397
|
Env extends Cloudflare.Env = Cloudflare.Env,
|
|
398
|
+
Config = unknown,
|
|
399
|
+
Command = never,
|
|
400
|
+
Change = never,
|
|
428
401
|
>(
|
|
429
|
-
definition:
|
|
430
|
-
|
|
431
|
-
|
|
402
|
+
definition:
|
|
403
|
+
| MutableRuntimeAgentDefinition<Env, Config, Command, Change>
|
|
404
|
+
| ReadonlyRuntimeAgentDefinition<Env, Config>,
|
|
405
|
+
): RuntimeAgentClass<Env, Command, Change> {
|
|
406
|
+
const resolveDefinitionHooks = (
|
|
407
|
+
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
408
|
+
): RuntimeAgentHooks<Env, Config, Command, Change> | undefined => {
|
|
409
|
+
const hooks = definition.hooks;
|
|
410
|
+
if (!hooks) return undefined;
|
|
411
|
+
return typeof hooks === "function"
|
|
412
|
+
? (hooks as (
|
|
413
|
+
ctx: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
414
|
+
) => RuntimeAgentHooks<Env, Config, Command, Change>)(context)
|
|
415
|
+
: hooks as RuntimeAgentHooks<Env, Config, Command, Change>;
|
|
416
|
+
};
|
|
432
417
|
|
|
433
418
|
const GeneratedRuntimeAgent = {
|
|
434
|
-
[definition.
|
|
419
|
+
[definition.name]: class extends AgentToolRuntimeKernel<Env> {
|
|
435
420
|
private hasLoadedRuntime = false;
|
|
436
421
|
private loadedRuntimeKey?: string;
|
|
437
422
|
private loading?: Promise<void>;
|
|
423
|
+
private temporaryLaunch?: TemporaryAgentLaunch<Config>;
|
|
424
|
+
private temporaryDispose?: () => Promise<void>;
|
|
425
|
+
private temporaryCleanup?: Promise<void>;
|
|
426
|
+
|
|
427
|
+
protected get role(): RuntimeAgentRole {
|
|
428
|
+
return this.parentPath.at(-1)?.className === definition.name
|
|
429
|
+
? "temporary"
|
|
430
|
+
: "primary";
|
|
431
|
+
}
|
|
438
432
|
|
|
439
433
|
// 作用:在 Kernel 真正消费 RuntimeSnapshot 前确保配置已完整提交。
|
|
440
434
|
// 调用:Submission 准入、恢复、审批续跑与 Runtime Workspace 路径调用。
|
|
441
|
-
// 原因:Session 本地读取不应支付 Config、
|
|
435
|
+
// 原因:Session 本地读取不应支付 Config、Assembly、MCP 和 Pi 装配成本。
|
|
442
436
|
protected ensureRuntimeReady(): Promise<void> {
|
|
443
437
|
return this.ensureConfig();
|
|
444
438
|
}
|
|
@@ -453,6 +447,28 @@ export function defineRuntimeAgent<
|
|
|
453
447
|
await this.ensureConfig(runtimeKey, options?.force === true);
|
|
454
448
|
}
|
|
455
449
|
|
|
450
|
+
async updateConfig(
|
|
451
|
+
command: Command,
|
|
452
|
+
): Promise<RuntimeConfigUpdateResult<Change>> {
|
|
453
|
+
if (this.role === "temporary") {
|
|
454
|
+
throw new Error("Temporary agents cannot update Runtime Config");
|
|
455
|
+
}
|
|
456
|
+
const update = definition.update;
|
|
457
|
+
if (!update) {
|
|
458
|
+
return { change: undefined as Change, runtime: "unchanged" };
|
|
459
|
+
}
|
|
460
|
+
const result = await update(this.createDefinitionContext(), command);
|
|
461
|
+
if (!result.changed) {
|
|
462
|
+
return { change: result.change, runtime: "unchanged" };
|
|
463
|
+
}
|
|
464
|
+
try {
|
|
465
|
+
await this.ensureConfig(undefined, true);
|
|
466
|
+
return { change: result.change, runtime: "reloaded" };
|
|
467
|
+
} catch {
|
|
468
|
+
return { change: result.change, runtime: "reload-failed" };
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
456
472
|
// 作用:确保 Runtime 可用后请求 Kernel 刷新 Session Context。
|
|
457
473
|
// 调用:Inbox 等 RPC 调用方在外部 Context 变更后调用。
|
|
458
474
|
// 待确认:当前 Kernel 的 `refreshContext` 只检查 Snapshot,并未执行实际刷新。
|
|
@@ -461,6 +477,11 @@ export function defineRuntimeAgent<
|
|
|
461
477
|
await this.refreshContext();
|
|
462
478
|
}
|
|
463
479
|
|
|
480
|
+
async getRuntimeAssembly(): Promise<RuntimeAssemblyView> {
|
|
481
|
+
await this.ensureRuntimeReady();
|
|
482
|
+
return this.readRuntimeAssembly();
|
|
483
|
+
}
|
|
484
|
+
|
|
464
485
|
dispatchMessage(
|
|
465
486
|
message: UIMessage,
|
|
466
487
|
delivery: MessageDelivery,
|
|
@@ -481,6 +502,13 @@ export function defineRuntimeAgent<
|
|
|
481
502
|
return super.cancelSubmissionById(submissionId, reason);
|
|
482
503
|
}
|
|
483
504
|
|
|
505
|
+
respondToolInteraction(
|
|
506
|
+
toolCallId: string,
|
|
507
|
+
response: unknown,
|
|
508
|
+
): Promise<{ ok: boolean }> {
|
|
509
|
+
return super.respondToolInteraction(toolCallId, response);
|
|
510
|
+
}
|
|
511
|
+
|
|
484
512
|
stopTurn(
|
|
485
513
|
requestId?: string,
|
|
486
514
|
reason?: string,
|
|
@@ -488,155 +516,366 @@ export function defineRuntimeAgent<
|
|
|
488
516
|
return super.stopTurn(requestId, reason);
|
|
489
517
|
}
|
|
490
518
|
|
|
519
|
+
protected override async prepareAgentToolRun(
|
|
520
|
+
input: unknown,
|
|
521
|
+
): Promise<string> {
|
|
522
|
+
if (this.role !== "temporary") {
|
|
523
|
+
throw new Error("Agent Tool runs require a temporary child facet");
|
|
524
|
+
}
|
|
525
|
+
const launch = parseTemporaryAgentLaunch<Config>(input);
|
|
526
|
+
this.temporaryLaunch = launch;
|
|
527
|
+
await this.ctx.storage.put(TEMPORARY_AGENT_LAUNCH_KEY, launch);
|
|
528
|
+
await this.reloadRuntime(launch.runtimeKey, { force: true });
|
|
529
|
+
return launch.task;
|
|
530
|
+
}
|
|
531
|
+
|
|
491
532
|
// 作用:把首次加载和按 key 重载合并成一个串行入口。
|
|
492
533
|
// 调用:Runtime readiness、Session 配置和重载都会调用。
|
|
493
534
|
// 原因:共享同一个 Promise 可合并并发首加载,显式切 key 则等待前序完成后再判断。
|
|
494
|
-
|
|
535
|
+
protected ensureConfig(
|
|
495
536
|
requestedRuntimeKey?: string,
|
|
496
537
|
force = false,
|
|
497
538
|
fromQueue = false,
|
|
498
539
|
): Promise<void> {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
540
|
+
if (this.loading && !fromQueue) {
|
|
541
|
+
if (!requestedRuntimeKey && !force) return this.loading;
|
|
542
|
+
|
|
543
|
+
// 显式 key 或强制刷新不能被正在进行的其他加载吞掉,必须等它结束后重新核对。
|
|
544
|
+
const queued = this.loading
|
|
545
|
+
.catch(() => undefined)
|
|
546
|
+
.then(() => {
|
|
547
|
+
if (
|
|
548
|
+
!force &&
|
|
549
|
+
this.hasLoadedRuntime &&
|
|
550
|
+
this.loadedRuntimeKey === requestedRuntimeKey
|
|
551
|
+
) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
return this.ensureConfig(
|
|
555
|
+
requestedRuntimeKey,
|
|
556
|
+
force,
|
|
557
|
+
true,
|
|
558
|
+
);
|
|
559
|
+
});
|
|
560
|
+
let tracked: Promise<void>;
|
|
561
|
+
tracked = queued.finally(() => {
|
|
562
|
+
if (this.loading === tracked) this.loading = undefined;
|
|
563
|
+
});
|
|
564
|
+
this.loading = tracked;
|
|
565
|
+
return tracked;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (
|
|
569
|
+
!force &&
|
|
570
|
+
this.hasLoadedRuntime &&
|
|
571
|
+
(!requestedRuntimeKey ||
|
|
572
|
+
requestedRuntimeKey === this.loadedRuntimeKey)
|
|
573
|
+
) {
|
|
574
|
+
return Promise.resolve();
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// 先创建局部 Promise,再赋给 `loading`,失败时也能在 finally 中放开重试。
|
|
578
|
+
const pending = (async () => {
|
|
579
|
+
this.runtimeLoad.begin();
|
|
580
|
+
const loadContext = this.createDefinitionContext();
|
|
581
|
+
const loaded = await withRuntimeLoadTimeout(
|
|
582
|
+
"definition.load",
|
|
583
|
+
() => (
|
|
584
|
+
definition.load as (
|
|
585
|
+
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
586
|
+
requestedRuntimeKey?: string,
|
|
587
|
+
) => Promise<LoadedRuntime<Config>>
|
|
588
|
+
)(
|
|
589
|
+
loadContext,
|
|
514
590
|
requestedRuntimeKey,
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
591
|
+
),
|
|
592
|
+
{ timeoutMs: RUNTIME_LOAD_TIMEOUT_MS },
|
|
593
|
+
);
|
|
594
|
+
const resolvedRuntimeKey = loaded.runtimeKey.trim();
|
|
595
|
+
if (!resolvedRuntimeKey) {
|
|
596
|
+
throw new Error("Resolved Runtime key must not be empty");
|
|
597
|
+
}
|
|
598
|
+
const context = this.createDefinitionContext({
|
|
599
|
+
value: loaded.config,
|
|
600
|
+
});
|
|
601
|
+
let tools = normalizeToolAssembly(await withRuntimeLoadTimeout(
|
|
602
|
+
"definition.tools",
|
|
603
|
+
() => (
|
|
604
|
+
definition.tools as (
|
|
605
|
+
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
606
|
+
config: Config,
|
|
607
|
+
) => ToolRegistry | ToolAssemblyResult | Promise<ToolRegistry | ToolAssemblyResult>
|
|
608
|
+
)(context, loaded.config),
|
|
609
|
+
{ timeoutMs: RUNTIME_LOAD_TIMEOUT_MS },
|
|
610
|
+
));
|
|
611
|
+
let hooks = resolveDefinitionHooks(context);
|
|
612
|
+
if (this.role === "temporary") {
|
|
613
|
+
this.temporaryDispose = tools.dispose;
|
|
614
|
+
tools = this.applyTemporaryToolPolicy(tools);
|
|
615
|
+
hooks = await this.createTemporaryHooks();
|
|
616
|
+
}
|
|
617
|
+
const candidate = await assembleRuntimeSnapshot({
|
|
618
|
+
ctx: context,
|
|
619
|
+
config: loaded.config,
|
|
620
|
+
tools,
|
|
621
|
+
resources: loaded.resources,
|
|
622
|
+
hooks,
|
|
518
623
|
});
|
|
624
|
+
|
|
625
|
+
await this.initCandidate(candidate);
|
|
626
|
+
this.hasLoadedRuntime = true;
|
|
627
|
+
this.loadedRuntimeKey = resolvedRuntimeKey;
|
|
628
|
+
this.runtimeLoad.complete();
|
|
629
|
+
// 提交之前 turnEvents 绑定还不存在,此前每一次广播都到不了 Host。
|
|
630
|
+
// Host 的会话列表把装配后的第一次投影当作「facet 已就绪」的信号。
|
|
631
|
+
await this.broadcastApprovals();
|
|
632
|
+
})().catch((error) => {
|
|
633
|
+
logRuntimeLoadFailure("runtime", error);
|
|
634
|
+
this.runtimeLoad.fail();
|
|
635
|
+
throw error;
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
if (fromQueue) return pending;
|
|
639
|
+
|
|
640
|
+
// 无论成功失败都清掉进行中标记,后续调用才可以重试或切 key。
|
|
519
641
|
let tracked: Promise<void>;
|
|
520
|
-
tracked =
|
|
642
|
+
tracked = pending.finally(() => {
|
|
521
643
|
if (this.loading === tracked) this.loading = undefined;
|
|
522
644
|
});
|
|
523
645
|
this.loading = tracked;
|
|
524
646
|
return tracked;
|
|
525
647
|
}
|
|
526
648
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
649
|
+
private applyTemporaryToolPolicy(
|
|
650
|
+
assembly: ToolAssemblyResult,
|
|
651
|
+
): ToolAssemblyResult {
|
|
652
|
+
const policy = assembly.surfacePolicy;
|
|
653
|
+
return {
|
|
654
|
+
...assembly,
|
|
655
|
+
bindings: assembly.bindings?.workspace
|
|
656
|
+
? { workspace: assembly.bindings.workspace }
|
|
657
|
+
: {},
|
|
658
|
+
memoryProfile: {
|
|
659
|
+
enabled: false,
|
|
660
|
+
memoryTokens: 2_000,
|
|
661
|
+
preferencesTokens: 500,
|
|
662
|
+
},
|
|
663
|
+
enabledSubagents: [],
|
|
664
|
+
surfacePolicy: {
|
|
665
|
+
allowsTool: (name) =>
|
|
666
|
+
temporaryAgentToolAllowed(name) &&
|
|
667
|
+
policy?.allowsTool?.(name) !== false,
|
|
668
|
+
allowsExtension: (extension) =>
|
|
669
|
+
temporaryAgentExtensionIsSafe(extension) &&
|
|
670
|
+
policy?.allowsExtension?.(extension) !== false,
|
|
671
|
+
},
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
private async createTemporaryHooks(): Promise<
|
|
676
|
+
RuntimeAgentHooks<Env, Config, Command, Change>
|
|
677
|
+
> {
|
|
678
|
+
const launch = this.temporaryLaunch ??
|
|
679
|
+
await this.ctx.storage.get<TemporaryAgentLaunch<Config>>(
|
|
680
|
+
TEMPORARY_AGENT_LAUNCH_KEY,
|
|
681
|
+
);
|
|
682
|
+
if (!launch) throw new Error("Temporary Agent is not initialized");
|
|
683
|
+
this.temporaryLaunch = launch;
|
|
684
|
+
return {
|
|
685
|
+
profileOverrides: () => ({
|
|
686
|
+
systemPrompt: launch.instructions,
|
|
687
|
+
executionLevel: "high",
|
|
688
|
+
}),
|
|
689
|
+
gateTool: async (request) => {
|
|
690
|
+
if (!requiresExecutionApproval(
|
|
691
|
+
launch.executionLevel,
|
|
692
|
+
request.requiredExecutionLevel,
|
|
693
|
+
)) return;
|
|
694
|
+
await this.requestParentTemporaryApproval(launch, request);
|
|
695
|
+
},
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
private async requestParentTemporaryApproval(
|
|
700
|
+
launch: TemporaryAgentLaunch<Config>,
|
|
701
|
+
request: {
|
|
702
|
+
toolCallId: string;
|
|
703
|
+
toolName: string;
|
|
704
|
+
input: unknown;
|
|
705
|
+
requiredExecutionLevel: ExecutionLevel;
|
|
706
|
+
signal: AbortSignal;
|
|
707
|
+
},
|
|
708
|
+
): Promise<void> {
|
|
709
|
+
if (request.signal.aborted) {
|
|
710
|
+
throw new Error("temporary agent was cancelled", {
|
|
711
|
+
cause: request.signal.reason,
|
|
712
|
+
});
|
|
534
713
|
}
|
|
714
|
+
const parent = await this.parentAgent(
|
|
715
|
+
this.constructor as ChatCapableAgentClass,
|
|
716
|
+
) as unknown as Pick<
|
|
717
|
+
RuntimeAgentControls,
|
|
718
|
+
"requestTemporaryAgentApproval" | "cancelTemporaryAgentApproval"
|
|
719
|
+
>;
|
|
720
|
+
const executionId =
|
|
721
|
+
`temporary-agent:${this.name}:${request.toolCallId}`;
|
|
722
|
+
let onAbort = () => {};
|
|
723
|
+
const aborted = new Promise<never>((_resolve, reject) => {
|
|
724
|
+
onAbort = () => {
|
|
725
|
+
void parent.cancelTemporaryAgentApproval(
|
|
726
|
+
executionId,
|
|
727
|
+
"temporary agent was cancelled",
|
|
728
|
+
);
|
|
729
|
+
reject(new Error("temporary agent was cancelled", {
|
|
730
|
+
cause: request.signal.reason,
|
|
731
|
+
}));
|
|
732
|
+
};
|
|
733
|
+
request.signal.addEventListener("abort", onAbort, { once: true });
|
|
734
|
+
});
|
|
735
|
+
try {
|
|
736
|
+
const decision = await Promise.race([
|
|
737
|
+
parent.requestTemporaryAgentApproval({
|
|
738
|
+
executionId,
|
|
739
|
+
subagentName: launch.subagentName,
|
|
740
|
+
requestId: `temporary-agent:${this.name}`,
|
|
741
|
+
toolCallId: request.toolCallId,
|
|
742
|
+
toolName: request.toolName,
|
|
743
|
+
executionLevel: launch.executionLevel,
|
|
744
|
+
requiredExecutionLevel: request.requiredExecutionLevel,
|
|
745
|
+
input: request.input,
|
|
746
|
+
}),
|
|
747
|
+
aborted,
|
|
748
|
+
]);
|
|
749
|
+
if (!decision.approved) {
|
|
750
|
+
throw new Error(
|
|
751
|
+
`temporary agent "${launch.subagentName}" Tool ` +
|
|
752
|
+
`"${request.toolName}" was rejected: ` +
|
|
753
|
+
`${decision.reason?.trim() || "rejected by user"}`,
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
} finally {
|
|
757
|
+
request.signal.removeEventListener("abort", onAbort);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
535
760
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
761
|
+
protected override cleanupAgentToolRun(): Promise<void> {
|
|
762
|
+
if (this.temporaryCleanup) return this.temporaryCleanup;
|
|
763
|
+
this.temporaryCleanup = (async () => {
|
|
764
|
+
if (!this.temporaryDispose) {
|
|
765
|
+
const launch = this.temporaryLaunch ??
|
|
766
|
+
await this.ctx.storage.get<TemporaryAgentLaunch<Config>>(
|
|
767
|
+
TEMPORARY_AGENT_LAUNCH_KEY,
|
|
768
|
+
);
|
|
769
|
+
if (launch) await this.ensureConfig(launch.runtimeKey);
|
|
770
|
+
}
|
|
771
|
+
await this.temporaryDispose?.();
|
|
772
|
+
})().catch((error) => {
|
|
773
|
+
console.warn("Temporary Agent resource cleanup failed", error);
|
|
774
|
+
});
|
|
775
|
+
return this.temporaryCleanup;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
protected createDefinitionContext(
|
|
779
|
+
runtimeConfig?: { value: Config },
|
|
780
|
+
): RuntimeAgentPlanningContext<
|
|
781
|
+
Env,
|
|
782
|
+
Command,
|
|
783
|
+
Change
|
|
784
|
+
> {
|
|
785
|
+
const agent = this;
|
|
786
|
+
return {
|
|
787
|
+
ctx: this.ctx,
|
|
788
|
+
env: this.env,
|
|
789
|
+
get name() {
|
|
790
|
+
return agent.name;
|
|
791
|
+
},
|
|
792
|
+
get parentPath() {
|
|
793
|
+
return agent.parentPath;
|
|
794
|
+
},
|
|
795
|
+
get role() {
|
|
796
|
+
return agent.role;
|
|
797
|
+
},
|
|
798
|
+
...(agent.role === "primary"
|
|
799
|
+
? {
|
|
800
|
+
updateConfig: (command: Command) =>
|
|
801
|
+
agent.updateConfig(command),
|
|
802
|
+
}
|
|
803
|
+
: {}),
|
|
804
|
+
runAgentTool: async (agentClass, options) =>
|
|
805
|
+
agent.runAgentTool(
|
|
806
|
+
agentClass,
|
|
807
|
+
options as never,
|
|
808
|
+
) as Promise<RuntimeAgentToolResult>,
|
|
809
|
+
clearAgentToolRuns: (options) =>
|
|
810
|
+
agent.clearAgentToolRuns(options),
|
|
811
|
+
executionLevel: () => agent.executionLevel(),
|
|
812
|
+
runTemporaryAgent: (request, runContext) => {
|
|
813
|
+
if (agent.role !== "primary" || !runtimeConfig) {
|
|
814
|
+
throw new Error("Temporary Agent cannot delegate again");
|
|
815
|
+
}
|
|
816
|
+
return agent.runTemporaryAgent(
|
|
817
|
+
request,
|
|
818
|
+
runContext,
|
|
819
|
+
async (normalized) => {
|
|
820
|
+
await agent.clearAgentToolRuns({
|
|
821
|
+
olderThan: Date.now() - AGENT_TOOL_RETENTION_MS,
|
|
822
|
+
status: [...TERMINAL_AGENT_TOOL_STATUSES],
|
|
823
|
+
});
|
|
824
|
+
const result = await agent.runAgentTool(
|
|
825
|
+
agent.constructor as ChatCapableAgentClass,
|
|
826
|
+
{
|
|
827
|
+
input: {
|
|
828
|
+
...normalized,
|
|
829
|
+
runtimeKey: agent.loadedRuntimeKey,
|
|
830
|
+
config: runtimeConfig.value,
|
|
831
|
+
executionLevel: agent.executionLevel(),
|
|
832
|
+
},
|
|
833
|
+
runId: `temporary-agent:${runContext.toolCallId}`,
|
|
834
|
+
parentToolCallId: runContext.toolCallId,
|
|
835
|
+
signal: runContext.signal,
|
|
836
|
+
inputPreview: normalized.task,
|
|
837
|
+
display: {
|
|
838
|
+
name: normalized.subagentName,
|
|
839
|
+
displayName: normalized.subagentName,
|
|
840
|
+
kind: "temporary",
|
|
841
|
+
},
|
|
842
|
+
},
|
|
843
|
+
);
|
|
844
|
+
if (result.status !== "completed") {
|
|
563
845
|
throw new Error(
|
|
564
|
-
|
|
846
|
+
result.error ??
|
|
847
|
+
`temporary agent ended with status ${result.status}`,
|
|
565
848
|
);
|
|
566
849
|
}
|
|
567
850
|
if (
|
|
568
|
-
|
|
569
|
-
|
|
851
|
+
typeof result.summary !== "string" ||
|
|
852
|
+
!result.summary.trim()
|
|
570
853
|
) {
|
|
571
854
|
throw new Error(
|
|
572
|
-
"
|
|
855
|
+
"temporary agent completed without final text",
|
|
573
856
|
);
|
|
574
857
|
}
|
|
575
|
-
|
|
858
|
+
return result.summary;
|
|
576
859
|
},
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
reloadRuntime: () => agent.ensureConfig(undefined, true),
|
|
581
|
-
// 作用:通过当前 Agent 启动一个受 SDK 管理的子运行。
|
|
582
|
-
// 调用:subagent 端口在委派 Agent Tool 时调用。
|
|
583
|
-
// 原因:保留 Agents SDK 的运行登记、事件、取消和清理边界。
|
|
584
|
-
runAgentTool: async (agentClass, options) =>
|
|
585
|
-
agent.runAgentTool(
|
|
586
|
-
agentClass,
|
|
587
|
-
options as never,
|
|
588
|
-
) as Promise<RuntimeAgentToolResult>,
|
|
589
|
-
// 作用:清理符合明确策略的已保留子运行。
|
|
590
|
-
// 调用:subagent 端口在执行运行保留期回收时调用。
|
|
591
|
-
// 原因:清理仍由 Agents SDK 执行,Runtime 不越过 SDK 直接修改子运行存储。
|
|
592
|
-
clearAgentToolRuns: (options) =>
|
|
593
|
-
agent.clearAgentToolRuns(options),
|
|
594
|
-
// 作用:返回当前已装配 User Agent 的执行档位。
|
|
595
|
-
// 调用:Plugin 在装配临时 Agent 审批桥时调用。
|
|
596
|
-
// 原因:只读 Profile,不再维护 Session 覆盖状态。
|
|
597
|
-
executionLevel: () => agent.executionLevel(),
|
|
598
|
-
// 作用:在当前 Session 中执行一次性临时 Agent。
|
|
599
|
-
// 调用:temporary-agent 端口在 Tool 需要调用内委派时调用。
|
|
600
|
-
// 原因:交给 Kernel 统一管理重名、取消和审批,不创建持久 facet。
|
|
601
|
-
runTemporaryAgent: (request, runContext, execute) =>
|
|
602
|
-
agent.runTemporaryAgent(request, runContext, execute),
|
|
603
|
-
},
|
|
604
|
-
requestedRuntimeKey,
|
|
605
|
-
);
|
|
606
|
-
|
|
607
|
-
// 只有原子提交成功后才更新已加载标记和 key。
|
|
608
|
-
await this.initConfig(config);
|
|
609
|
-
this.hasLoadedRuntime = true;
|
|
610
|
-
this.loadedRuntimeKey =
|
|
611
|
-
resolvedRuntimeKey ?? requestedRuntimeKey;
|
|
612
|
-
this.completeRuntimeLoad();
|
|
613
|
-
})().catch((error) => {
|
|
614
|
-
this.failRuntimeLoad();
|
|
615
|
-
throw error;
|
|
616
|
-
});
|
|
617
|
-
|
|
618
|
-
if (fromQueue) return pending;
|
|
619
|
-
|
|
620
|
-
// 无论成功失败都清掉进行中标记,后续调用才可以重试或切 key。
|
|
621
|
-
let tracked: Promise<void>;
|
|
622
|
-
tracked = pending.finally(() => {
|
|
623
|
-
if (this.loading === tracked) this.loading = undefined;
|
|
624
|
-
});
|
|
625
|
-
this.loading = tracked;
|
|
626
|
-
return tracked;
|
|
860
|
+
);
|
|
861
|
+
},
|
|
862
|
+
};
|
|
627
863
|
}
|
|
628
864
|
},
|
|
629
|
-
}[definition.
|
|
865
|
+
}[definition.name];
|
|
630
866
|
|
|
631
|
-
if (GeneratedRuntimeAgent.name !== definition.
|
|
867
|
+
if (GeneratedRuntimeAgent.name !== definition.name) {
|
|
632
868
|
throw new Error(
|
|
633
|
-
`Runtime Agent class name mismatch: expected "${definition.
|
|
869
|
+
`Runtime Agent class name mismatch: expected "${definition.name}", got "${GeneratedRuntimeAgent.name}"`,
|
|
634
870
|
);
|
|
635
871
|
}
|
|
636
872
|
|
|
637
873
|
// Decorator syntax renames this computed class during Worker bundling.
|
|
638
874
|
// Apply the same decorator function after class-name inference instead.
|
|
639
875
|
const callableContext = {} as ClassMethodDecoratorContext;
|
|
876
|
+
callable()(GeneratedRuntimeAgent.prototype.reloadRuntime, callableContext);
|
|
877
|
+
callable()(GeneratedRuntimeAgent.prototype.updateConfig, callableContext);
|
|
878
|
+
callable()(GeneratedRuntimeAgent.prototype.getRuntimeAssembly, callableContext);
|
|
640
879
|
callable()(GeneratedRuntimeAgent.prototype.dispatchMessage, callableContext);
|
|
641
880
|
callable()(
|
|
642
881
|
GeneratedRuntimeAgent.prototype.steerQueuedSubmission,
|
|
@@ -646,9 +885,17 @@ export function defineRuntimeAgent<
|
|
|
646
885
|
GeneratedRuntimeAgent.prototype.cancelSubmissionById,
|
|
647
886
|
callableContext,
|
|
648
887
|
);
|
|
888
|
+
callable()(
|
|
889
|
+
GeneratedRuntimeAgent.prototype.respondToolInteraction,
|
|
890
|
+
callableContext,
|
|
891
|
+
);
|
|
649
892
|
callable()(GeneratedRuntimeAgent.prototype.stopTurn, callableContext);
|
|
650
893
|
|
|
651
|
-
return GeneratedRuntimeAgent as RuntimeAgentClass<
|
|
894
|
+
return GeneratedRuntimeAgent as unknown as RuntimeAgentClass<
|
|
895
|
+
Env,
|
|
896
|
+
Command,
|
|
897
|
+
Change
|
|
898
|
+
>;
|
|
652
899
|
}
|
|
653
900
|
|
|
654
901
|
// #endregion
|