@springbrand/agent-runtime 0.1.3-alpha.0 → 0.1.3-alpha.10
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 +61 -27
- package/src/kernel/approval-lifecycle.ts +41 -6
- package/src/kernel/bindings.ts +99 -12
- package/src/kernel/extensions.ts +1 -1
- package/src/kernel/interaction-lifecycle.ts +395 -0
- package/src/kernel/profile.ts +3 -4
- 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 -67
- package/src/lib/mcp.ts +7 -3
- package/src/lib/prompt.ts +1 -1
- package/src/lib/telemetry-dev.ts +7 -4
- package/src/pi/assembly/context.ts +4 -6
- package/src/pi/assembly/extensions.ts +11 -22
- package/src/pi/assembly/snapshot.ts +17 -9
- package/src/pi/message/contract.ts +7 -0
- package/src/pi/message/conversion.ts +9 -1
- package/src/pi/runtime-adapter/assembly.ts +42 -97
- package/src/pi/runtime-adapter/execution.ts +216 -21
- 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 +39 -33
- package/src/pi/tool/core-host.ts +28 -30
- package/src/pi/tool/core.ts +37 -124
- package/src/pi/tool/gateway.ts +54 -0
- package/src/pi/tool/index.ts +2 -0
- package/src/pi/tool/mcp.ts +98 -70
- package/src/pi/tool/schedule.ts +86 -20
- 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/runtime-assembler.ts +797 -0
- package/src/runtime-definition.ts +175 -0
- package/src/runtime.ts +840 -208
- package/src/tool-registry.ts +143 -0
- package/src/workspace-versioning.ts +46 -0
- package/src/plugins.ts +0 -1033
package/src/pi/tool/compiler.ts
CHANGED
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
import type { ApprovalReceipt } from "../../kernel/receipts";
|
|
7
7
|
import { boundDurableToolOutput } from "../../layers/context/budget/gate";
|
|
8
8
|
import {
|
|
9
|
-
EXECUTION_LEVELS,
|
|
10
9
|
type ExecutionLevel,
|
|
11
10
|
} from "../../lib/execution-level";
|
|
12
11
|
|
|
@@ -14,19 +13,51 @@ import {
|
|
|
14
13
|
|
|
15
14
|
// #region Public contracts
|
|
16
15
|
|
|
17
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* 声明一个 Tool 的结果由客户端投递,而不是由 `execute()` 产出。
|
|
18
|
+
*
|
|
19
|
+
* 带这个字段的 Tool 会在执行链里 park 住,等宿主经 `respondToolInteraction` 把响应送进来,
|
|
20
|
+
* 再用 `settle` 把响应映射成这次 `toolCallId` 的权威 ToolResult。它的 `execute` 不会被调用。
|
|
21
|
+
*
|
|
22
|
+
* 这是 AI SDK 里「没有 execute 的 user-interaction tool」的等价物;差别是我们 park 住整个 Turn,
|
|
23
|
+
* 而不是让 tool part 悬空到下一次请求 —— 我们的 transcript 是服务端权威的,悬空的 tool_use
|
|
24
|
+
* 会让下一次模型调用非法。
|
|
25
|
+
*/
|
|
26
|
+
export interface PiToolInteractionSpec {
|
|
27
|
+
/** 校验客户端响应体;不通过则拒绝投递,park 保持不变。 */
|
|
28
|
+
readonly validateResponse: (response: unknown) => boolean;
|
|
29
|
+
/** 把通过校验的响应映射成 ToolResult;缺省是原样回传。 */
|
|
30
|
+
readonly settle?: (
|
|
31
|
+
input: unknown,
|
|
32
|
+
response: unknown,
|
|
33
|
+
) => AgentToolResult<unknown>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 描述一个尚未进入最终 Tool Surface 和结算包装的 Pi 工具。 */
|
|
18
37
|
export interface PiToolCandidate {
|
|
19
38
|
readonly owner: string;
|
|
20
|
-
readonly authorized: boolean;
|
|
21
39
|
readonly tool: AgentTool<any, any>;
|
|
40
|
+
/** Conservative maximum used in the stable Runtime descriptor. */
|
|
22
41
|
readonly requiredExecutionLevel: ExecutionLevel;
|
|
42
|
+
/** Trusted parameter-level policy, evaluated before approval or dispatch. */
|
|
43
|
+
readonly requiredExecutionLevelForInput?: (
|
|
44
|
+
input: unknown,
|
|
45
|
+
) => ExecutionLevel | Promise<ExecutionLevel>;
|
|
46
|
+
/**
|
|
47
|
+
* 无条件需要人来决定:不看执行档位矩阵,每次调用都 park 出审批。
|
|
48
|
+
*
|
|
49
|
+
* 档位差是「够不够格自己跑」,不是「该不该问人」。花用户钱、改变账户
|
|
50
|
+
* 状态这类工具,一旦 Agent 档位被 `allow_level` 永久拉高就会静默执行,
|
|
51
|
+
* 那是失效不是降级。`deny` 仍然优先,被 deny 的工具根本不会注入。
|
|
52
|
+
*/
|
|
53
|
+
readonly alwaysRequiresApproval?: boolean;
|
|
23
54
|
readonly summary?: string;
|
|
24
55
|
readonly source?: ApprovalReceipt["source"];
|
|
56
|
+
readonly interaction?: PiToolInteractionSpec;
|
|
25
57
|
}
|
|
26
58
|
|
|
27
59
|
/** 控制候选 Pi 工具如何被编译为可执行工具集。 */
|
|
28
60
|
export interface CompilePiToolsOptions {
|
|
29
|
-
readonly deny?: readonly string[];
|
|
30
61
|
readonly governance?: PiToolGovernance;
|
|
31
62
|
readonly settle: (
|
|
32
63
|
call: SettledPiToolCall,
|
|
@@ -248,7 +279,7 @@ export function createPiToolGovernance(
|
|
|
248
279
|
}
|
|
249
280
|
|
|
250
281
|
// 为一个候选工具包上输出限额、持久化结算、重试治理和遥测。
|
|
251
|
-
// `compilePiTools()`
|
|
282
|
+
// `compilePiTools()` 对最终 Tool Surface 中的每个候选项调用。
|
|
252
283
|
// 一个共享包装边界可确保所有工具无论成功还是失败都经过 settle,不能由各工具自行选择是否持久化。
|
|
253
284
|
function governedTool(
|
|
254
285
|
candidate: PiToolCandidate,
|
|
@@ -402,11 +433,9 @@ function governedTool(
|
|
|
402
433
|
}
|
|
403
434
|
|
|
404
435
|
/**
|
|
405
|
-
*
|
|
436
|
+
* 把已经 Tool Surface 最终化的候选项包成可执行工具集。
|
|
406
437
|
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
* 工具名是模型调用和结算的唯一键,所以冲突必须在组装时失败,不能用后来者静默覆盖。
|
|
438
|
+
* `PiTurnAdapter` 在每个 Turn 及手动重试时用它创建执行治理包装。
|
|
410
439
|
*/
|
|
411
440
|
export function compilePiTools(
|
|
412
441
|
candidates: readonly PiToolCandidate[],
|
|
@@ -415,30 +444,7 @@ export function compilePiTools(
|
|
|
415
444
|
if (!options?.settle) {
|
|
416
445
|
throw new Error("Pi Tool settlement port is required");
|
|
417
446
|
}
|
|
418
|
-
|
|
419
|
-
const tools: AgentTool<any, any>[] = [];
|
|
420
|
-
const owners = new Map<string, string>();
|
|
421
|
-
|
|
422
|
-
for (const candidate of candidates) {
|
|
423
|
-
if (!EXECUTION_LEVELS.includes(candidate.requiredExecutionLevel)) {
|
|
424
|
-
throw new Error(
|
|
425
|
-
`Pi Tool "${candidate.tool.name}" has invalid requiredExecutionLevel`,
|
|
426
|
-
);
|
|
427
|
-
}
|
|
428
|
-
if (!candidate.authorized || deny.has(candidate.tool.name)) continue;
|
|
429
|
-
|
|
430
|
-
const existingOwner = owners.get(candidate.tool.name);
|
|
431
|
-
if (existingOwner !== undefined) {
|
|
432
|
-
throw new Error(
|
|
433
|
-
`duplicate tool key "${candidate.tool.name}" (${candidate.owner} collides with ${existingOwner})`,
|
|
434
|
-
);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
owners.set(candidate.tool.name, candidate.owner);
|
|
438
|
-
tools.push(governedTool(candidate, options));
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return tools;
|
|
447
|
+
return candidates.map((candidate) => governedTool(candidate, options));
|
|
442
448
|
}
|
|
443
449
|
|
|
444
450
|
// #endregion
|
package/src/pi/tool/core-host.ts
CHANGED
|
@@ -1,52 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createCodemodeRuntime,
|
|
3
|
-
DynamicWorkerExecutor,
|
|
4
|
-
truncateResult,
|
|
5
|
-
} from "@cloudflare/codemode";
|
|
6
1
|
import {
|
|
7
2
|
createWorkspaceStateBackend,
|
|
8
3
|
type WorkspaceFsLike,
|
|
9
4
|
} from "@cloudflare/shell";
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
import { createExecuteRuntime } from "@cloudflare/think/tools/execute";
|
|
6
|
+
import type {
|
|
7
|
+
RuntimeCodeExecutionPort,
|
|
8
|
+
WorkspacePort,
|
|
9
|
+
} from "../../kernel/bindings";
|
|
14
10
|
|
|
15
11
|
// 本文件沿用 `../../index.ts` 入口定义的 Workspace、Port 和 Tool Candidate 术语。
|
|
16
12
|
|
|
17
13
|
const CODEMODE_SANDBOX_TIMEOUT_MS = 55_000;
|
|
18
14
|
|
|
19
15
|
/**
|
|
20
|
-
* 把宿主的 Worker Loader、出站网络和 Workspace
|
|
16
|
+
* 把宿主的 Worker Loader、出站网络和 Workspace 组装成代码执行 Port。
|
|
21
17
|
*
|
|
22
18
|
* Worker 宿主在具备 Durable Object state 和完整平台绑定时调用,然后把返回值交给 Runtime 工具组装。
|
|
23
19
|
*
|
|
24
|
-
*
|
|
20
|
+
* Think 的独立 execute factory 接受显式宿主参数,不要求 Agent 继承 Think;这里只借它组装 Codemode Runtime、Dynamic Worker executor 和已限定范围的 Workspace state connector。
|
|
25
21
|
*/
|
|
26
|
-
export function
|
|
22
|
+
export function createWorkspaceCodeExecutionPort(options: {
|
|
27
23
|
readonly ctx: DurableObjectState;
|
|
28
24
|
readonly loader: WorkerLoader;
|
|
29
25
|
readonly outbound: Fetcher;
|
|
30
26
|
readonly workspace: WorkspacePort;
|
|
31
|
-
}):
|
|
32
|
-
const
|
|
27
|
+
}): RuntimeCodeExecutionPort {
|
|
28
|
+
const { tool } = createExecuteRuntime({
|
|
33
29
|
ctx: options.ctx,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
new StateConnector(
|
|
42
|
-
options.ctx,
|
|
43
|
-
createWorkspaceStateBackend(
|
|
44
|
-
options.workspace as unknown as WorkspaceFsLike,
|
|
45
|
-
),
|
|
46
|
-
),
|
|
47
|
-
],
|
|
30
|
+
loader: options.loader,
|
|
31
|
+
globalOutbound: options.outbound,
|
|
32
|
+
// 先于外层 60s 截止结束,给 Runtime RPC 结算和 Worker 释放留出时间。
|
|
33
|
+
timeout: CODEMODE_SANDBOX_TIMEOUT_MS,
|
|
34
|
+
state: createWorkspaceStateBackend(
|
|
35
|
+
options.workspace as unknown as WorkspaceFsLike,
|
|
36
|
+
),
|
|
48
37
|
name: "execute",
|
|
49
|
-
transformResult: truncateResult,
|
|
50
38
|
});
|
|
51
|
-
|
|
39
|
+
const execute = tool.execute;
|
|
40
|
+
if (typeof execute !== "function") {
|
|
41
|
+
throw new Error("Think createExecuteRuntime returned a non-executable tool");
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
execute: (input) => Promise.resolve(execute(input, {
|
|
45
|
+
toolCallId: "execute",
|
|
46
|
+
messages: [],
|
|
47
|
+
context: undefined,
|
|
48
|
+
})),
|
|
49
|
+
};
|
|
52
50
|
}
|
package/src/pi/tool/core.ts
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
+
import { createQuickActionTools } from "@cloudflare/think/tools/browser";
|
|
1
2
|
import type {
|
|
2
3
|
AgentTool,
|
|
3
4
|
AgentToolResult,
|
|
4
5
|
} from "@earendil-works/pi-agent-core";
|
|
5
6
|
import { Type } from "@earendil-works/pi-ai";
|
|
6
|
-
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
browserMarkdown,
|
|
11
|
-
browserScrape,
|
|
12
|
-
type QuickActionPage,
|
|
13
|
-
} from "agents/browser";
|
|
14
|
-
import type { RuntimeBrowserPort } from "../../kernel/bindings";
|
|
7
|
+
import type {
|
|
8
|
+
RuntimeBrowserPort,
|
|
9
|
+
RuntimeCodeExecutionPort,
|
|
10
|
+
} from "../../kernel/bindings";
|
|
15
11
|
import { serializeOutput } from "../../lib/artifacts";
|
|
16
12
|
import type { PiLoadedExtension } from "../assembly/extensions";
|
|
13
|
+
import { aiToolToPi } from "./ai-adapter";
|
|
17
14
|
import type { PiToolCandidate } from "./compiler";
|
|
15
|
+
import {
|
|
16
|
+
toolRegistryFromPiCandidates,
|
|
17
|
+
type ToolRegistry,
|
|
18
|
+
} from "../../tool-registry";
|
|
18
19
|
|
|
19
20
|
// 本文件沿用 `../../index.ts` 入口定义的 Extension、Port 和 Tool Candidate 术语。
|
|
20
21
|
|
|
@@ -30,128 +31,32 @@ function result(details: unknown): AgentToolResult<unknown> {
|
|
|
30
31
|
|
|
31
32
|
// #region Browser Quick Actions
|
|
32
33
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const BROWSER_TOOL_LABELS: Readonly<Record<string, string>> = {
|
|
35
|
+
browser_markdown: "Read web page",
|
|
36
|
+
browser_extract: "Extract web data",
|
|
37
|
+
browser_links: "List web links",
|
|
38
|
+
browser_scrape: "Scrape web elements",
|
|
36
39
|
};
|
|
37
|
-
const browserPageParameters = Type.Object(pageParameters);
|
|
38
|
-
const browserExtractParameters = Type.Object({
|
|
39
|
-
...pageParameters,
|
|
40
|
-
prompt: Type.Optional(Type.String({ minLength: 1 })),
|
|
41
|
-
schema: Type.Optional(Type.Unknown()),
|
|
42
|
-
});
|
|
43
|
-
const browserScrapeParameters = Type.Object({
|
|
44
|
-
...pageParameters,
|
|
45
|
-
selectors: Type.Array(Type.String({ minLength: 1 }), {
|
|
46
|
-
minItems: 1,
|
|
47
|
-
}),
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// 把工具输入收窄为 Browser Quick Action 接受的页面来源。
|
|
51
|
-
// 四个 Browser Quick Action execute 方法在调用 Agents SDK 前共用它。
|
|
52
|
-
// 实际运行时再拒绝空输入,而同时给出 url 和 html 时优先 url,不能把不完整来源传给宿主绑定。
|
|
53
|
-
function page(input: {
|
|
54
|
-
url?: string;
|
|
55
|
-
html?: string;
|
|
56
|
-
}): QuickActionPage {
|
|
57
|
-
if (input.url) return { url: input.url };
|
|
58
|
-
if (input.html) return { html: input.html };
|
|
59
|
-
throw new Error("Provide either 'url' or 'html'");
|
|
60
|
-
}
|
|
61
40
|
|
|
62
41
|
/**
|
|
63
42
|
* 为 Cloudflare Browser Run 的四个一次性 Quick Action 创建 Pi 工具候选项。
|
|
64
43
|
*
|
|
65
44
|
* Runtime 在宿主提供 Browser port 时调用,模型分别用它读取 Markdown、抽取数据、列出链接或按选择器抓取。
|
|
66
45
|
*
|
|
67
|
-
* Cloudflare 官方将 Quick Actions 定位为只需 browser binding
|
|
46
|
+
* Cloudflare 官方将 Quick Actions 定位为只需 browser binding 的无状态单次操作,这里直接复用官方工厂。
|
|
68
47
|
*/
|
|
69
48
|
export function browserQuickActionPiToolCandidates(
|
|
70
49
|
browser: RuntimeBrowserPort,
|
|
71
50
|
): PiToolCandidate[] {
|
|
72
|
-
|
|
73
|
-
name
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
async execute(_toolCallId, input, signal) {
|
|
82
|
-
signal?.throwIfAborted();
|
|
83
|
-
return result(await browserMarkdown(browser, page(input)));
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
const extract: AgentTool<typeof browserExtractParameters> = {
|
|
87
|
-
name: "browser_extract",
|
|
88
|
-
label: "Extract web data",
|
|
89
|
-
description:
|
|
90
|
-
"Extract structured data from a web page using AI. Describe what you want in 'prompt'. Passing a JSON Schema in 'schema' is strongly recommended — without one the extractor often fails to produce JSON.",
|
|
91
|
-
parameters: browserExtractParameters,
|
|
92
|
-
// 按自然语言提示或 JSON Schema 从页面抽取数据。
|
|
93
|
-
// Pi 工具循环在模型选择 `browser_extract` 时调用,至少需要 prompt 或 schema 之一。
|
|
94
|
-
// schema 必须转成 Browser Run 期望的 `json_schema` response_format,而空抽取要求必须在发起请求前失败。
|
|
95
|
-
async execute(
|
|
96
|
-
_toolCallId,
|
|
97
|
-
{ prompt, schema, ...input },
|
|
98
|
-
signal,
|
|
99
|
-
) {
|
|
100
|
-
signal?.throwIfAborted();
|
|
101
|
-
if (!prompt && schema === undefined) {
|
|
102
|
-
throw new Error("Provide either 'prompt' or 'schema'");
|
|
103
|
-
}
|
|
104
|
-
return result(await browserExtract(browser, {
|
|
105
|
-
...page(input),
|
|
106
|
-
prompt,
|
|
107
|
-
response_format: schema === undefined
|
|
108
|
-
? undefined
|
|
109
|
-
: { type: "json_schema", schema },
|
|
110
|
-
}));
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
const links: AgentTool<typeof browserPageParameters> = {
|
|
114
|
-
name: "browser_links",
|
|
115
|
-
label: "List web links",
|
|
116
|
-
description:
|
|
117
|
-
"Return every link found on a web page (including ones not visible). Useful for discovering pages to follow.",
|
|
118
|
-
parameters: browserPageParameters,
|
|
119
|
-
// 列出 URL 或 HTML 页面中的链接。
|
|
120
|
-
// Pi 工具循环在模型选择 `browser_links` 时调用,调用前允许 Turn 取消。
|
|
121
|
-
// 保留 Agents SDK 的原始结果形状,让统一 result 边界负责文本投影而不在此处二次整形。
|
|
122
|
-
async execute(_toolCallId, input, signal) {
|
|
123
|
-
signal?.throwIfAborted();
|
|
124
|
-
return result(await browserLinks(browser, page(input)));
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
const scrape: AgentTool<typeof browserScrapeParameters> = {
|
|
128
|
-
name: "browser_scrape",
|
|
129
|
-
label: "Scrape web elements",
|
|
130
|
-
description:
|
|
131
|
-
"Scrape specific elements from a web page by CSS selector. Returns the matched elements' text, HTML, and attributes.",
|
|
132
|
-
parameters: browserScrapeParameters,
|
|
133
|
-
// 按 CSS 选择器抓取 URL 或 HTML 页面的指定元素。
|
|
134
|
-
// Pi 工具循环在模型选择 `browser_scrape` 时调用,并把简化的字符串列表传入。
|
|
135
|
-
// Browser Run 需要 `{ selector }` 对象列表,因此这个适配只在边界做一次形状转换。
|
|
136
|
-
async execute(
|
|
137
|
-
_toolCallId,
|
|
138
|
-
{ selectors, ...input },
|
|
139
|
-
signal,
|
|
140
|
-
) {
|
|
141
|
-
signal?.throwIfAborted();
|
|
142
|
-
return result(await browserScrape(browser, {
|
|
143
|
-
...page(input),
|
|
144
|
-
elements: selectors.map((selector) => ({ selector })),
|
|
145
|
-
}));
|
|
146
|
-
},
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
return [markdown, extract, links, scrape].map((tool) => ({
|
|
150
|
-
owner: "core:browser",
|
|
151
|
-
authorized: true,
|
|
152
|
-
requiredExecutionLevel: "low",
|
|
153
|
-
tool,
|
|
154
|
-
}));
|
|
51
|
+
return Object.entries(createQuickActionTools({ browser })).map(
|
|
52
|
+
([name, tool]) => ({
|
|
53
|
+
owner: "core:browser",
|
|
54
|
+
requiredExecutionLevel: "low",
|
|
55
|
+
tool: aiToolToPi(name, tool, {
|
|
56
|
+
label: BROWSER_TOOL_LABELS[name] ?? name,
|
|
57
|
+
}),
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
155
60
|
}
|
|
156
61
|
|
|
157
62
|
// #endregion
|
|
@@ -188,7 +93,6 @@ export function listExtensionsPiToolCandidate(
|
|
|
188
93
|
};
|
|
189
94
|
return {
|
|
190
95
|
owner: "core:extensions",
|
|
191
|
-
authorized: true,
|
|
192
96
|
requiredExecutionLevel: "low",
|
|
193
97
|
tool,
|
|
194
98
|
};
|
|
@@ -210,12 +114,13 @@ const CODEMODE_EXECUTE_TIMEOUT_MS = 60_000;
|
|
|
210
114
|
/**
|
|
211
115
|
* 把 Cloudflare Codemode Runtime handle 包装为高风险 Pi 代码执行工具候选项。
|
|
212
116
|
*
|
|
213
|
-
*
|
|
117
|
+
* Tool Surface 收到 Host 已组装的 Code Execution Port 后调用,
|
|
118
|
+
* 模型再通过 `execute` 运行代码。
|
|
214
119
|
*
|
|
215
120
|
* Codemode 代码可访问出站网络和已配置 connector,因此必须保留 high 档和 codemode source 标记,不能降级成普通本地计算工具。
|
|
216
121
|
*/
|
|
217
122
|
export function codeExecutionPiToolCandidate(
|
|
218
|
-
runtime:
|
|
123
|
+
runtime: RuntimeCodeExecutionPort,
|
|
219
124
|
): PiToolCandidate {
|
|
220
125
|
const tool: AgentTool<typeof executeParameters> = {
|
|
221
126
|
name: "execute",
|
|
@@ -267,7 +172,6 @@ export function codeExecutionPiToolCandidate(
|
|
|
267
172
|
};
|
|
268
173
|
return {
|
|
269
174
|
owner: "core:codemode",
|
|
270
|
-
authorized: true,
|
|
271
175
|
requiredExecutionLevel: "high",
|
|
272
176
|
source: "codemode",
|
|
273
177
|
summary: "Run JavaScript with network and configured connector access",
|
|
@@ -275,4 +179,13 @@ export function codeExecutionPiToolCandidate(
|
|
|
275
179
|
};
|
|
276
180
|
}
|
|
277
181
|
|
|
182
|
+
/** 从 Codemode Runtime Port 生成 `execute` Tool。 */
|
|
183
|
+
export function createCodeExecutionTool(
|
|
184
|
+
runtime: RuntimeCodeExecutionPort,
|
|
185
|
+
): ToolRegistry {
|
|
186
|
+
return toolRegistryFromPiCandidates([
|
|
187
|
+
codeExecutionPiToolCandidate(runtime),
|
|
188
|
+
]);
|
|
189
|
+
}
|
|
190
|
+
|
|
278
191
|
// #endregion
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { RuntimeGatewaySession } from "../../kernel/bindings";
|
|
2
|
+
import type { PiToolCandidate } from "./compiler";
|
|
3
|
+
import { createPiMcpToolCandidate } from "./mcp";
|
|
4
|
+
|
|
5
|
+
const GATEWAY_TOOLS = [
|
|
6
|
+
"search_capabilities",
|
|
7
|
+
"execute_capability",
|
|
8
|
+
] as const;
|
|
9
|
+
|
|
10
|
+
/** Builds the two platform Gateway tools from one authenticated logical MCP Session. */
|
|
11
|
+
export function createPiGatewayToolCandidates(
|
|
12
|
+
session: RuntimeGatewaySession,
|
|
13
|
+
): PiToolCandidate[] {
|
|
14
|
+
const tools = new Map(session.tools.map((tool) => [tool.name, tool]));
|
|
15
|
+
if (
|
|
16
|
+
tools.size !== GATEWAY_TOOLS.length ||
|
|
17
|
+
GATEWAY_TOOLS.some((name) => !tools.has(name))
|
|
18
|
+
) {
|
|
19
|
+
throw new Error("Connector Gateway returned an invalid MCP catalog");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return GATEWAY_TOOLS.map((name) => {
|
|
23
|
+
const tool = tools.get(name)!;
|
|
24
|
+
const execute = name === "execute_capability";
|
|
25
|
+
return createPiMcpToolCandidate(
|
|
26
|
+
{ ...tool, serverId: "gateway" },
|
|
27
|
+
(input, signal) => session.callTool(name, input, signal),
|
|
28
|
+
{
|
|
29
|
+
owner: "gateway",
|
|
30
|
+
modelName: name,
|
|
31
|
+
requiredExecutionLevel: execute ? "high" : "safe",
|
|
32
|
+
...(execute
|
|
33
|
+
? {
|
|
34
|
+
requiredExecutionLevelForInput: async (input: unknown) => {
|
|
35
|
+
const reference = input && typeof input === "object" &&
|
|
36
|
+
!Array.isArray(input)
|
|
37
|
+
? (input as Record<string, unknown>).name
|
|
38
|
+
: undefined;
|
|
39
|
+
if (typeof reference !== "string" || !reference) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"Gateway Capability Reference is not verified",
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
return (await session.resolveCapabilityRisk(reference)) ===
|
|
45
|
+
"none"
|
|
46
|
+
? "safe" as const
|
|
47
|
+
: "high" as const;
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
: {}),
|
|
51
|
+
},
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
}
|
package/src/pi/tool/index.ts
CHANGED
|
@@ -24,9 +24,11 @@ export * from "./base";
|
|
|
24
24
|
export * from "./compiler";
|
|
25
25
|
export * from "./core";
|
|
26
26
|
export * from "./core-host";
|
|
27
|
+
export * from "./gateway";
|
|
27
28
|
export * from "./mcp";
|
|
28
29
|
export * from "./schedule";
|
|
29
30
|
export * from "./skill";
|
|
30
31
|
export * from "./subagent";
|
|
31
32
|
export * from "./workspace-sandbox";
|
|
33
|
+
export * from "./workspace-revision";
|
|
32
34
|
export * from "./web-search";
|