@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
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import type { SqlTaggedTemplate } from "agents/chat";
|
|
2
|
+
|
|
3
|
+
// Tool Interaction 的统一定义见 ./index.ts。
|
|
4
|
+
// #region 状态与行类型
|
|
5
|
+
export type ToolInteractionStatus = "pending" | "responded" | "cancelled";
|
|
6
|
+
|
|
7
|
+
export interface StoredToolInteraction {
|
|
8
|
+
interactionId: string;
|
|
9
|
+
submissionId: string;
|
|
10
|
+
requestId: string;
|
|
11
|
+
toolCallId: string;
|
|
12
|
+
toolName: string;
|
|
13
|
+
inputJson: string;
|
|
14
|
+
status: ToolInteractionStatus;
|
|
15
|
+
responseJson: string | null;
|
|
16
|
+
createdAt: number;
|
|
17
|
+
respondedAt: number | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface NewToolInteraction {
|
|
21
|
+
interactionId: string;
|
|
22
|
+
submissionId: string;
|
|
23
|
+
requestId: string;
|
|
24
|
+
toolCallId: string;
|
|
25
|
+
toolName: string;
|
|
26
|
+
inputJson: string;
|
|
27
|
+
status: ToolInteractionStatus;
|
|
28
|
+
createdAt: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type ToolInteractionRow = {
|
|
32
|
+
interaction_id: string;
|
|
33
|
+
submission_id: string;
|
|
34
|
+
request_id: string;
|
|
35
|
+
tool_call_id: string;
|
|
36
|
+
tool_name: string;
|
|
37
|
+
input_json: string;
|
|
38
|
+
status: string;
|
|
39
|
+
response_json: string | null;
|
|
40
|
+
created_at: number;
|
|
41
|
+
responded_at: number | null;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// #endregion
|
|
45
|
+
// #region 行映射
|
|
46
|
+
// 把 SQLite 的 Interaction 行转成 Runtime 对象。
|
|
47
|
+
// find 与 findPending* 查到记录后调用,上层因而不需要理解 snake_case 列名。
|
|
48
|
+
// 状态由表内字符串转成联合类型;新增列或状态时必须同步核对类型、SELECT 和映射。
|
|
49
|
+
function mapRow(row: ToolInteractionRow): StoredToolInteraction {
|
|
50
|
+
return {
|
|
51
|
+
interactionId: row.interaction_id,
|
|
52
|
+
submissionId: row.submission_id,
|
|
53
|
+
requestId: row.request_id,
|
|
54
|
+
toolCallId: row.tool_call_id,
|
|
55
|
+
toolName: row.tool_name,
|
|
56
|
+
inputJson: row.input_json,
|
|
57
|
+
status: row.status as ToolInteractionStatus,
|
|
58
|
+
responseJson: row.response_json,
|
|
59
|
+
createdAt: row.created_at,
|
|
60
|
+
respondedAt: row.responded_at,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// #endregion
|
|
65
|
+
// #region Repository
|
|
66
|
+
export class ToolInteractionRepository {
|
|
67
|
+
// 保存当前 Agent SQLite 的查询入口。
|
|
68
|
+
// RuntimeDatabase 构造时调用,InteractionLifecycle 随后共享这个 Repository。
|
|
69
|
+
// Interaction 必须与所属 Submission 在同一 Agent 存储中查询,不能跨 Durable Object 拼接状态。
|
|
70
|
+
constructor(private readonly sql: SqlTaggedTemplate) {}
|
|
71
|
+
|
|
72
|
+
// 按 interactionId 读取一条完整 Interaction,不存在时返回 null。
|
|
73
|
+
// InteractionLifecycle 在请求去重、响应、取消和收尾时调用,调用方必须处理 null。
|
|
74
|
+
// interaction_id 是主键,LIMIT 1 明确只消费一行。
|
|
75
|
+
find(interactionId: string): StoredToolInteraction | null {
|
|
76
|
+
const row = this.sql<ToolInteractionRow>`
|
|
77
|
+
SELECT interaction_id, submission_id, request_id,
|
|
78
|
+
tool_call_id, tool_name, input_json,
|
|
79
|
+
status, response_json, created_at, responded_at
|
|
80
|
+
FROM pi_tool_interactions
|
|
81
|
+
WHERE interaction_id = ${interactionId}
|
|
82
|
+
LIMIT 1
|
|
83
|
+
`[0];
|
|
84
|
+
return row ? mapRow(row) : null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 持久化一条新的 pending Interaction。
|
|
88
|
+
// InteractionLifecycle.ensurePending 在准入事务内确认没有同一记录后调用。
|
|
89
|
+
// 主键和 (submission_id, tool_call_id) 唯一约束是持久化去重防线,不能用覆盖式 INSERT 掩盖冲突。
|
|
90
|
+
insert(interaction: NewToolInteraction): void {
|
|
91
|
+
this.sql`
|
|
92
|
+
INSERT INTO pi_tool_interactions (
|
|
93
|
+
interaction_id, submission_id, request_id,
|
|
94
|
+
tool_call_id, tool_name, input_json,
|
|
95
|
+
status, created_at
|
|
96
|
+
) VALUES (
|
|
97
|
+
${interaction.interactionId},
|
|
98
|
+
${interaction.submissionId},
|
|
99
|
+
${interaction.requestId},
|
|
100
|
+
${interaction.toolCallId},
|
|
101
|
+
${interaction.toolName},
|
|
102
|
+
${interaction.inputJson},
|
|
103
|
+
${interaction.status},
|
|
104
|
+
${interaction.createdAt}
|
|
105
|
+
)
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 只把 pending Interaction 落成 responded 或 cancelled,并记录响应体与时间。
|
|
110
|
+
// InteractionLifecycle 在收到客户端响应或判定取消时调用,迟到的重复投递不应覆盖首次结果。
|
|
111
|
+
// WHERE status='pending' 实现首次响应胜出,不能去掉这个条件;调用方在事务后重读来确认是否真的生效。
|
|
112
|
+
settle(
|
|
113
|
+
interactionId: string,
|
|
114
|
+
status: Exclude<ToolInteractionStatus, "pending">,
|
|
115
|
+
respondedAt: number,
|
|
116
|
+
responseJson?: string,
|
|
117
|
+
): void {
|
|
118
|
+
this.sql`
|
|
119
|
+
UPDATE pi_tool_interactions
|
|
120
|
+
SET status = ${status},
|
|
121
|
+
response_json = ${responseJson ?? null},
|
|
122
|
+
responded_at = ${respondedAt}
|
|
123
|
+
WHERE interaction_id = ${interactionId}
|
|
124
|
+
AND status = 'pending'
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 按创建顺序列出某次 Submission 仍等待客户端响应的 interactionId。
|
|
129
|
+
// InteractionLifecycle.cancelPending 在取消或终止 Turn 时调用,随后逐条追加取消恢复事实。
|
|
130
|
+
// ORDER BY created_at 保留原始顺序,不能依赖 SQLite 未声明的默认行顺序。
|
|
131
|
+
listPendingForSubmission(submissionId: string): string[] {
|
|
132
|
+
return this.sql<{ interaction_id: string }>`
|
|
133
|
+
SELECT interaction_id
|
|
134
|
+
FROM pi_tool_interactions
|
|
135
|
+
WHERE submission_id = ${submissionId}
|
|
136
|
+
AND status = 'pending'
|
|
137
|
+
ORDER BY created_at ASC
|
|
138
|
+
`.map((row) => row.interaction_id);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 只在某个 toolCallId 唯一匹配一条活跃 pending Interaction 时返回该记录。
|
|
142
|
+
// Runtime.respondToolInteraction 的入口调用它 —— 前端只有 toolCallId,不知道 submissionId。
|
|
143
|
+
// toolCallId 只在单个 Submission 内唯一,LIMIT 2 用最小查询识别跨 Submission 重名;
|
|
144
|
+
// 不能用 LIMIT 1 静默选中任意一条,那会把答案投给错的那次调用。口径与 ApprovalRepository 同名方法一致。
|
|
145
|
+
findPendingByToolCallId(toolCallId: string): StoredToolInteraction | null {
|
|
146
|
+
const matches = this.sql<ToolInteractionRow>`
|
|
147
|
+
SELECT interaction.interaction_id, interaction.submission_id,
|
|
148
|
+
interaction.request_id, interaction.tool_call_id,
|
|
149
|
+
interaction.tool_name, interaction.input_json,
|
|
150
|
+
interaction.status, interaction.response_json,
|
|
151
|
+
interaction.created_at, interaction.responded_at
|
|
152
|
+
FROM pi_tool_interactions interaction
|
|
153
|
+
JOIN pi_submissions submission
|
|
154
|
+
ON submission.submission_id = interaction.submission_id
|
|
155
|
+
WHERE interaction.tool_call_id = ${toolCallId}
|
|
156
|
+
AND interaction.status = 'pending'
|
|
157
|
+
AND submission.status NOT IN (
|
|
158
|
+
'completed', 'aborted', 'skipped', 'error'
|
|
159
|
+
)
|
|
160
|
+
LIMIT 2
|
|
161
|
+
`;
|
|
162
|
+
const only = matches.length === 1 ? matches[0] : undefined;
|
|
163
|
+
return only ? mapRow(only) : null;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 列出所属 Submission 仍活跃的全部 pending Interaction。
|
|
167
|
+
// Runtime 启动扫描调用它,用来判断哪些 park 还需要续跑依据。
|
|
168
|
+
// 与 findPendingByToolCallId 使用同样的 JOIN 和状态条件,修改其一时必须核对另一个。
|
|
169
|
+
listPendingActive(): StoredToolInteraction[] {
|
|
170
|
+
return this.sql<ToolInteractionRow>`
|
|
171
|
+
SELECT interaction.interaction_id, interaction.submission_id,
|
|
172
|
+
interaction.request_id, interaction.tool_call_id,
|
|
173
|
+
interaction.tool_name, interaction.input_json,
|
|
174
|
+
interaction.status, interaction.response_json,
|
|
175
|
+
interaction.created_at, interaction.responded_at
|
|
176
|
+
FROM pi_tool_interactions interaction
|
|
177
|
+
JOIN pi_submissions submission
|
|
178
|
+
ON submission.submission_id = interaction.submission_id
|
|
179
|
+
WHERE interaction.status = 'pending'
|
|
180
|
+
AND submission.status IN ('pending', 'running')
|
|
181
|
+
ORDER BY interaction.created_at ASC
|
|
182
|
+
`.map(mapRow);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// #endregion
|
package/src/db/schema.ts
CHANGED
|
@@ -4,6 +4,8 @@ import type { SqlTaggedTemplate } from "agents/chat";
|
|
|
4
4
|
// 创建当前 Runtime 需要但尚不存在的 SQLite 表。
|
|
5
5
|
// AgentRuntimeKernel 构造时通过 RuntimeDatabase.initializeSchema 调用,重复启动依赖 IF NOT EXISTS 保留现有表。
|
|
6
6
|
// pi_approvals 有一次显式的 risk → 四档升级;步骤均可重入,中断后下次初始化会继续。
|
|
7
|
+
// pi_tool_interactions 是 client-settled tool 的 pending 索引:结果的权威副本仍在 pi_tool_settlements,
|
|
8
|
+
// 这张表只回答「这次工具调用还等不等得到客户端响应」。
|
|
7
9
|
export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
8
10
|
sql`CREATE TABLE IF NOT EXISTS pi_message_ui (
|
|
9
11
|
message_id TEXT PRIMARY KEY,
|
|
@@ -119,6 +121,19 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
119
121
|
END`;
|
|
120
122
|
sql`ALTER TABLE pi_approvals DROP COLUMN risk`;
|
|
121
123
|
}
|
|
124
|
+
sql`CREATE TABLE IF NOT EXISTS pi_tool_interactions (
|
|
125
|
+
interaction_id TEXT PRIMARY KEY,
|
|
126
|
+
submission_id TEXT NOT NULL,
|
|
127
|
+
request_id TEXT NOT NULL,
|
|
128
|
+
tool_call_id TEXT NOT NULL,
|
|
129
|
+
tool_name TEXT NOT NULL,
|
|
130
|
+
input_json TEXT NOT NULL,
|
|
131
|
+
status TEXT NOT NULL,
|
|
132
|
+
response_json TEXT,
|
|
133
|
+
created_at INTEGER NOT NULL,
|
|
134
|
+
responded_at INTEGER,
|
|
135
|
+
UNIQUE (submission_id, tool_call_id)
|
|
136
|
+
)`;
|
|
122
137
|
sql`CREATE TABLE IF NOT EXISTS pi_recovery_milestones (
|
|
123
138
|
submission_id TEXT NOT NULL,
|
|
124
139
|
seq INTEGER NOT NULL,
|
|
@@ -180,6 +180,17 @@ export class SubmissionRepository {
|
|
|
180
180
|
);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
+
// 按创建顺序列出还在排队或运行的 Submission id。
|
|
184
|
+
// 换装配前的「是不是全都停在等人」判断调用它,逐条核对每一条的人机等待。
|
|
185
|
+
// 状态集合与 countUnfinished 必须一致,修改其一时另一个也要跟着改。
|
|
186
|
+
listUnfinishedIds(): string[] {
|
|
187
|
+
return this.sql<{ submission_id: string }>`
|
|
188
|
+
SELECT submission_id FROM pi_submissions
|
|
189
|
+
WHERE status IN ('pending', 'running')
|
|
190
|
+
ORDER BY created_at ASC, rowid ASC
|
|
191
|
+
`.map((row) => row.submission_id);
|
|
192
|
+
}
|
|
193
|
+
|
|
183
194
|
findRunning(): StoredSubmission | null {
|
|
184
195
|
const id = this.sql<{ submission_id: string }>`
|
|
185
196
|
SELECT submission_id FROM pi_submissions
|
|
@@ -252,6 +263,24 @@ export class SubmissionRepository {
|
|
|
252
263
|
return updated.length === 1;
|
|
253
264
|
}
|
|
254
265
|
|
|
266
|
+
// 把一条已 pin 的 Submission 换到另一对 revision / descriptor 上。
|
|
267
|
+
// Runtime 在「停在人机等待期间换了装配」之后调用,必须与那次装配迁移里程碑同事务。
|
|
268
|
+
// 与 pinAssembly 的区别就是它要求已经 pin 过:首次 pin 走 pinAssembly,
|
|
269
|
+
// 这里不接受空值,避免把一次漏写的准入 pin 伪装成一次迁移。
|
|
270
|
+
repinAssembly(id: string, revision: string, descriptor: string): boolean {
|
|
271
|
+
const updated = this.sql<{ submission_id: string }>`
|
|
272
|
+
UPDATE pi_submissions
|
|
273
|
+
SET assembly_revision = ${revision},
|
|
274
|
+
assembly_descriptor = ${descriptor}
|
|
275
|
+
WHERE submission_id = ${id}
|
|
276
|
+
AND assembly_revision <> ''
|
|
277
|
+
AND assembly_descriptor <> ''
|
|
278
|
+
AND status IN ('pending', 'running')
|
|
279
|
+
RETURNING submission_id
|
|
280
|
+
`;
|
|
281
|
+
return updated.length === 1;
|
|
282
|
+
}
|
|
283
|
+
|
|
255
284
|
// 只在当前状态属于 from 时把 Submission 切换到 to,否则返回 false。
|
|
256
285
|
// SubmissionLifecycle 开始 Turn 时调用,调用方用返回值识别过期或重复的状态切换。
|
|
257
286
|
// Cloudflare SQLite 查询是同步的,两条语句之间不会让其他事件交错;UPDATE 再次带旧状态条件,不能去掉这层幂等保护。
|
package/src/index.ts
CHANGED
|
@@ -22,11 +22,10 @@
|
|
|
22
22
|
* - `SubAgent` 是由父 Agent 发起、但拥有独立执行上下文的子任务执行者。
|
|
23
23
|
* - `canonical transcript` 是 Pi 持久化和恢复 Turn 时使用的权威消息历史。
|
|
24
24
|
* - `admission` 是提示进入 Turn 前的接纳、去重和状态登记流程。
|
|
25
|
-
* - `
|
|
26
|
-
* - `
|
|
27
|
-
* - `
|
|
28
|
-
* - `
|
|
29
|
-
* - `Port` 是 Runtime 调用外部能力时依赖的最小接口。
|
|
25
|
+
* - `defineRuntimeAgent.load` 返回 config 和已加载 Resource。
|
|
26
|
+
* - `defineRuntimeAgent.tools` 是 Host 第一层 Tool 注册表声明。
|
|
27
|
+
* - `assembleRuntimeSnapshot` 消费该输入与 hooks,产出候选 Snapshot。
|
|
28
|
+
* - `Port` 是 Runtime 调用外部能力时依赖的最小接口(Definition 作者不直接装配)。
|
|
30
29
|
* - `RuntimeBindings` 是本次装配选中的 Port 和可执行对象集合。
|
|
31
30
|
* - `RuntimeBuilder` 是包内实现,用来校验贡献并生成候选结果。
|
|
32
31
|
* - `RuntimeCandidate` 是尚未生效的候选结果和提交前检查。
|
|
@@ -38,11 +37,8 @@
|
|
|
38
37
|
*
|
|
39
38
|
* Snapshot 不允许替换已选集合,但不承诺把每个 Port 的内部对象深冻结。
|
|
40
39
|
*
|
|
41
|
-
* 正常调用顺序是 `
|
|
42
|
-
*
|
|
43
|
-
* 应用只创建 `AgentConfig` 和 Plugin。
|
|
44
|
-
*
|
|
45
|
-
* Runtime 独占校验、排序和原子提交。
|
|
40
|
+
* 正常调用顺序是 `assemble → validate → freeze → guard → commit`。
|
|
41
|
+
* Runtime 独占跨能力校验和原子提交。
|
|
46
42
|
*
|
|
47
43
|
* @packageDocumentation
|
|
48
44
|
*/
|
|
@@ -50,23 +46,44 @@ export * from "./kernel/bindings";
|
|
|
50
46
|
export * from "./kernel/extensions";
|
|
51
47
|
export * from "./kernel/profile";
|
|
52
48
|
export * from "./kernel/receipts";
|
|
49
|
+
export * from "./kernel/runtime-config";
|
|
50
|
+
export type { RuntimeAssemblyView } from "./kernel/runtime-assembly-view";
|
|
53
51
|
export * from "./runtime-agent";
|
|
54
52
|
export * from "./kernel/state";
|
|
55
53
|
export * from "./lib/execution-level";
|
|
56
|
-
export { definePlugin } from "./plugins";
|
|
57
54
|
export type {
|
|
58
|
-
|
|
59
|
-
AgentPlugin,
|
|
60
|
-
AgentPluginSpec,
|
|
61
|
-
PluginKind,
|
|
62
|
-
PluginPreparation,
|
|
63
|
-
PreparedPlugin,
|
|
55
|
+
RuntimeAssemblyInput,
|
|
64
56
|
RuntimeDegradation,
|
|
65
57
|
RuntimeExtensionContribution,
|
|
66
58
|
RuntimeProfileContribution,
|
|
67
59
|
RuntimeSkillContribution,
|
|
68
60
|
RuntimeToolSurfacePolicy,
|
|
69
|
-
} from "./
|
|
61
|
+
} from "./runtime-assembler";
|
|
62
|
+
export { assembleRuntimeSnapshot, toolRegistryPiToolCandidates } from "./runtime-assembler";
|
|
63
|
+
export type {
|
|
64
|
+
PlatformToolContext,
|
|
65
|
+
PlatformToolRegistry,
|
|
66
|
+
PlatformToolSpec,
|
|
67
|
+
ProfileOverrides,
|
|
68
|
+
ResolvedConnectors,
|
|
69
|
+
ResolvedResources,
|
|
70
|
+
RuntimeAgentContext,
|
|
71
|
+
RuntimeAgentHooks,
|
|
72
|
+
RuntimeSettings,
|
|
73
|
+
RuntimeToolBindings,
|
|
74
|
+
ToolAssemblyResult,
|
|
75
|
+
ToolContext,
|
|
76
|
+
ToolRegistry,
|
|
77
|
+
ToolSpec,
|
|
78
|
+
} from "./runtime-definition";
|
|
79
|
+
export {
|
|
80
|
+
emptyPlatformToolRegistry,
|
|
81
|
+
emptyToolRegistry,
|
|
82
|
+
mergeToolRegistries,
|
|
83
|
+
normalizeToolAssembly,
|
|
84
|
+
piCandidateToToolSpec,
|
|
85
|
+
toolRegistryFromPiCandidates,
|
|
86
|
+
} from "./tool-registry";
|
|
70
87
|
export type { ModelOption } from "./lib/model-catalog";
|
|
71
88
|
export {
|
|
72
89
|
assembleSubagentPrompt,
|
|
@@ -92,16 +109,30 @@ export type {
|
|
|
92
109
|
SettledPiToolCall,
|
|
93
110
|
} from "./pi/tool";
|
|
94
111
|
export { basePiToolCandidates } from "./pi/tool";
|
|
95
|
-
export { schedulePiToolCandidates } from "./pi/tool";
|
|
96
112
|
export {
|
|
113
|
+
createMemoryTools,
|
|
114
|
+
memoryPiToolCandidate,
|
|
115
|
+
} from "./pi/tool";
|
|
116
|
+
export {
|
|
117
|
+
createScheduleTools,
|
|
118
|
+
schedulePiToolCandidates,
|
|
119
|
+
} from "./pi/tool";
|
|
120
|
+
export {
|
|
121
|
+
createSandboxTools,
|
|
122
|
+
createWorkspaceTools,
|
|
97
123
|
sandboxPiToolCandidates,
|
|
98
124
|
workspacePiToolCandidates,
|
|
99
125
|
} from "./pi/tool";
|
|
100
|
-
export {
|
|
126
|
+
export {
|
|
127
|
+
createSubagentTools,
|
|
128
|
+
subagentPiToolCandidates,
|
|
129
|
+
} from "./pi/tool";
|
|
101
130
|
export { skillPiToolCandidates } from "./pi/tool";
|
|
102
131
|
export type { PiSkillBinding } from "./pi/tool";
|
|
103
132
|
export {
|
|
104
133
|
browserQuickActionPiToolCandidates,
|
|
134
|
+
createCodeExecutionTool,
|
|
135
|
+
codeExecutionPiToolCandidate,
|
|
105
136
|
} from "./pi/tool";
|
|
106
137
|
export {
|
|
107
138
|
createWorkspaceCodeExecutionPort,
|
|
@@ -113,10 +144,11 @@ export {
|
|
|
113
144
|
export type {
|
|
114
145
|
TemporaryAgentApprovalDecision,
|
|
115
146
|
TemporaryAgentApprovalRequest,
|
|
116
|
-
|
|
147
|
+
TemporaryAgentLaunch,
|
|
117
148
|
TemporaryAgentRequest,
|
|
118
149
|
TemporaryAgentRunContext,
|
|
119
150
|
} from "./layers/orchestration/temporary-agent/core";
|
|
151
|
+
export { TEMPORARY_AGENT_LAUNCH_KEY } from "./layers/orchestration/temporary-agent/core";
|
|
120
152
|
export {
|
|
121
153
|
temporaryAgentExtensionIsSafe,
|
|
122
154
|
temporaryAgentToolAllowed,
|
|
@@ -101,7 +101,10 @@ interface ApprovalLifecycleOptions<
|
|
|
101
101
|
export class ApprovalLifecycle<
|
|
102
102
|
TSubmission extends ApprovalSubmission,
|
|
103
103
|
> {
|
|
104
|
-
private readonly waiters = new Map<
|
|
104
|
+
private readonly waiters = new Map<
|
|
105
|
+
string,
|
|
106
|
+
{ readonly release: () => void; readonly discard: () => void }
|
|
107
|
+
>();
|
|
105
108
|
|
|
106
109
|
/**
|
|
107
110
|
* 接好审批流程需要的宿主依赖。
|
|
@@ -217,6 +220,27 @@ export class ApprovalLifecycle<
|
|
|
217
220
|
return this.wait(pending.approval, signal);
|
|
218
221
|
}
|
|
219
222
|
|
|
223
|
+
/**
|
|
224
|
+
* 丢弃某条提交在内存里的全部审批等待器。
|
|
225
|
+
*
|
|
226
|
+
* @remarks
|
|
227
|
+
* 宿主在 park 期间换掉装配、中断内存执行器之后调用。持久审批一个字都不动:
|
|
228
|
+
* 被丢弃的只是「唤醒这一条执行器」的能力。
|
|
229
|
+
*
|
|
230
|
+
* 不丢弃的后果很具体:决定到来时 `decide` 会看见等待器,把 Turn 唤回那条已经
|
|
231
|
+
* 退场的旧执行器上,于是既拿不到新能力,也永远不会走持久续跑 —— Turn 就停在
|
|
232
|
+
* running 上不动了。等待器以 `PiTurnInterruptedError` 拒绝,工具编译器认得它,
|
|
233
|
+
* 不会为此写一条权威的错误结算。
|
|
234
|
+
*/
|
|
235
|
+
discardWaiters(submissionId: string): void {
|
|
236
|
+
for (
|
|
237
|
+
const executionId of this.options.db.approvals
|
|
238
|
+
.listPendingForSubmission(submissionId)
|
|
239
|
+
) {
|
|
240
|
+
this.waiters.get(executionId)?.discard();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
220
244
|
/**
|
|
221
245
|
* 在已批准工具结果落盘后,确认对应恢复调度已经完成。
|
|
222
246
|
*
|
|
@@ -364,7 +388,7 @@ export class ApprovalLifecycle<
|
|
|
364
388
|
await this.options.onApprovalsChanged();
|
|
365
389
|
|
|
366
390
|
if (waiter) {
|
|
367
|
-
waiter();
|
|
391
|
+
waiter.release();
|
|
368
392
|
return { ok: true };
|
|
369
393
|
}
|
|
370
394
|
|
|
@@ -540,10 +564,21 @@ export class ApprovalLifecycle<
|
|
|
540
564
|
return;
|
|
541
565
|
}
|
|
542
566
|
signal?.addEventListener("abort", abort, { once: true });
|
|
543
|
-
this.waiters.set(approval.executionId,
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
567
|
+
this.waiters.set(approval.executionId, {
|
|
568
|
+
release: () => {
|
|
569
|
+
signal?.removeEventListener("abort", abort);
|
|
570
|
+
this.waiters.delete(approval.executionId);
|
|
571
|
+
resolve();
|
|
572
|
+
},
|
|
573
|
+
// 只把等待器摘掉,不去 settle 这个 Promise。让它继续挂着,park 住的
|
|
574
|
+
// 那次 execute 就永远不会往下走 —— 无论是拒绝(Pi 会把它当成工具失败,
|
|
575
|
+
// 接着再要一次模型输出)还是放行(工具会真的跑一遍),都会让一条本该
|
|
576
|
+
// 退场的执行器继续做事。它所属的 adapter 已经被中止并丢弃,这个悬着的
|
|
577
|
+
// Promise 随它一起变成垃圾。
|
|
578
|
+
discard: () => {
|
|
579
|
+
signal?.removeEventListener("abort", abort);
|
|
580
|
+
this.waiters.delete(approval.executionId);
|
|
581
|
+
},
|
|
547
582
|
});
|
|
548
583
|
});
|
|
549
584
|
}
|
package/src/kernel/bindings.ts
CHANGED
|
@@ -522,6 +522,41 @@ export interface RuntimeSandboxPort {
|
|
|
522
522
|
|
|
523
523
|
// #region Runtime 服务端口
|
|
524
524
|
|
|
525
|
+
/** Gateway MCP 发现后可供 Pi 装配的安全 Tool 描述。 */
|
|
526
|
+
export interface RuntimeGatewayMcpTool {
|
|
527
|
+
readonly name: string;
|
|
528
|
+
readonly title?: string;
|
|
529
|
+
readonly description?: string;
|
|
530
|
+
readonly inputSchema?: Record<string, unknown>;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/** Gateway safe Catalog 中经过认证的 Action Risk。 */
|
|
534
|
+
export type RuntimeGatewayActionRisk = "none" | "high";
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* 一次 Agent Runtime 独占的 Gateway MCP 逻辑 Session。
|
|
538
|
+
*
|
|
539
|
+
* Runtime Grant 由实现闭包持有;本接口只暴露发现、调用和可信风险解析,
|
|
540
|
+
* 因此 Grant 不会进入 Profile、Snapshot 描述或 transcript。
|
|
541
|
+
*/
|
|
542
|
+
export interface RuntimeGatewaySession {
|
|
543
|
+
readonly tools: readonly RuntimeGatewayMcpTool[];
|
|
544
|
+
callTool(
|
|
545
|
+
name: string,
|
|
546
|
+
input: Readonly<Record<string, unknown>>,
|
|
547
|
+
signal?: AbortSignal,
|
|
548
|
+
): Promise<unknown>;
|
|
549
|
+
resolveCapabilityRisk(
|
|
550
|
+
reference: string,
|
|
551
|
+
): Promise<RuntimeGatewayActionRisk>;
|
|
552
|
+
close(): Promise<void>;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Host 在 Runtime 启动时用它 mint Grant 并打开唯一 Gateway MCP Session。 */
|
|
556
|
+
export interface RuntimeGatewayPort {
|
|
557
|
+
open(runtimeId: string): Promise<RuntimeGatewaySession>;
|
|
558
|
+
}
|
|
559
|
+
|
|
525
560
|
/**
|
|
526
561
|
* 描述一条模型可见的定时任务。
|
|
527
562
|
*
|
|
@@ -911,6 +946,8 @@ export interface RuntimeSkillSourceBinding {
|
|
|
911
946
|
export interface RuntimeBindings {
|
|
912
947
|
provider: RuntimeProviderPort;
|
|
913
948
|
platform: RuntimePlatformPort;
|
|
949
|
+
/** Secret-capability binding; implementations must keep Runtime Grant in closure state. */
|
|
950
|
+
gateway?: RuntimeGatewayPort;
|
|
914
951
|
workspace?: WorkspacePort;
|
|
915
952
|
memory?: RuntimeMemoryPort;
|
|
916
953
|
skills: RuntimeSkillBindings;
|