@springbrand/agent-runtime 0.2.0-alpha.32 → 0.2.0-alpha.36
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/index.ts +0 -1
- package/src/adapter/cloudflare/universal-agent/tools.ts +17 -30
- package/src/index.ts +5 -32
- package/src/kernel/bindings.ts +6 -6
- package/src/kernel/interaction-lifecycle.ts +5 -5
- package/src/pi/assembly/extensions.ts +23 -38
- package/src/pi/assembly/snapshot.ts +7 -1
- package/src/pi/runtime-adapter/assembly.ts +19 -14
- package/src/pi/runtime-adapter/execution.ts +7 -10
- package/src/pi/runtime-adapter/recovery.ts +18 -40
- package/src/pi/runtime-adapter/transcript.ts +5 -13
- package/src/pi/tool/base.ts +0 -15
- package/src/pi/tool/compiler.ts +1 -3
- package/src/pi/tool/core-host.ts +125 -41
- package/src/pi/tool/core.ts +8 -3
- package/src/pi/tool/nested-tools.ts +42 -0
- package/src/pi/tool/schedule.ts +0 -9
- package/src/pi/tool/skill.ts +10 -21
- package/src/pi/tool/subagent.ts +0 -13
- package/src/pi/tool/workspace-revision.ts +0 -12
- package/src/pi/tool/workspace-sandbox.ts +0 -10
- package/src/pi/turn/tool-recovery.ts +2 -2
- package/src/runtime-agent.ts +5 -9
- package/src/runtime-assembler.ts +57 -89
- package/src/runtime-definition.ts +30 -20
- package/src/runtime.ts +19 -7
- package/src/kernel/tool-surface.ts +0 -41
- package/src/tool-registry.ts +0 -143
package/src/pi/tool/core-host.ts
CHANGED
|
@@ -4,24 +4,57 @@ import {
|
|
|
4
4
|
} from "@cloudflare/shell";
|
|
5
5
|
import { createBrowserTools } from "@cloudflare/think/tools/browser";
|
|
6
6
|
import { createExecuteRuntime } from "@cloudflare/think/tools/execute";
|
|
7
|
-
import {
|
|
7
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
8
|
+
import type { Usage } from "@earendil-works/pi-ai";
|
|
9
|
+
import type { ToolSet } from "ai";
|
|
8
10
|
import type {
|
|
9
11
|
RuntimeBrowserPort,
|
|
10
12
|
RuntimeCodeExecutionPort,
|
|
11
13
|
WorkspacePort,
|
|
12
14
|
} from "../../kernel/bindings";
|
|
13
|
-
import type {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from "
|
|
15
|
+
import type { RuntimeCodeExecutionFactory } from "../../kernel/bindings";
|
|
16
|
+
import { serializeOutput } from "../../lib/artifacts";
|
|
17
|
+
import type { PiToolCandidate } from "./compiler";
|
|
18
|
+
import { piCandidatesToAiTools } from "./nested-tools";
|
|
17
19
|
|
|
18
20
|
// 本文件沿用 `../../index.ts` 入口定义的 Workspace、Port 和 Tool Candidate 术语。
|
|
19
21
|
|
|
20
22
|
const CODEMODE_SANDBOX_TIMEOUT_MS = 55_000;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
|
|
24
|
+
function directoryEntry(name: string, label: string): string {
|
|
25
|
+
const singleLineLabel = label.replaceAll(/\s+/g, " ").trim().replaceAll("`", "'");
|
|
26
|
+
return `- \`${name}\` — ${singleLineLabel}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function codeExecutionDescription(
|
|
30
|
+
candidates: readonly PiToolCandidate[],
|
|
31
|
+
): string {
|
|
32
|
+
const list = (
|
|
33
|
+
entries: readonly { readonly name: string; readonly label: string }[],
|
|
34
|
+
) => entries.length > 0
|
|
35
|
+
? entries.map(({ name, label }) => directoryEntry(name, label)).join("\n")
|
|
36
|
+
: "- None.";
|
|
37
|
+
|
|
38
|
+
return [
|
|
39
|
+
"Execute plain JavaScript in a sandbox using the exact Tool directory below.",
|
|
40
|
+
"",
|
|
41
|
+
"## `tools.*` Available",
|
|
42
|
+
list(candidates.map(({ tool }) => ({
|
|
43
|
+
name: tool.name,
|
|
44
|
+
label: tool.label ?? tool.name,
|
|
45
|
+
}))),
|
|
46
|
+
"",
|
|
47
|
+
"Call only the methods listed above through `tools.*`; never guess or construct a method name.",
|
|
48
|
+
"Use `codemode.describe(\"tools.method\")` when you need the exact input type for a listed method.",
|
|
49
|
+
"`codemode.search` cannot add methods to `tools.*` or load top-level Tools; it searches only connector methods and snippets already installed in this Code Mode Runtime.",
|
|
50
|
+
"Use `state.*` for the Workspace filesystem. Every method takes one object argument, for example `state.readFile({ path })` and `state.writeFile({ path, content })`.",
|
|
51
|
+
"Wrap raw fetch, random values, time, and other nondeterministic work in `codemode.step(name, fn)` so replay runs them once.",
|
|
52
|
+
"Some connector methods pause for approval and resume automatically. Do not re-issue paused code.",
|
|
53
|
+
"Keep all code outside connector calls and `codemode.step` deterministic.",
|
|
54
|
+
"Raw `fetch` is available inside `codemode.step(...)`; prefer connector SDKs when one owns the target.",
|
|
55
|
+
"There is no Node.js `require`, `process`, package manager, or Python runtime.",
|
|
56
|
+
].join("\n");
|
|
57
|
+
}
|
|
25
58
|
|
|
26
59
|
/**
|
|
27
60
|
* 宿主的 Browser Rendering 绑定,只取本仓真正用到的那一面。
|
|
@@ -40,18 +73,61 @@ export interface RuntimeBrowserBinding {
|
|
|
40
73
|
*
|
|
41
74
|
* Think 的独立 execute factory 接受显式宿主参数,不要求 Agent 继承 Think;这里只借它组装 Codemode Runtime、Dynamic Worker executor 和已限定范围的 Workspace state connector。
|
|
42
75
|
*/
|
|
43
|
-
function
|
|
44
|
-
return
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
76
|
+
function result(details: unknown): AgentToolResult<unknown> {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: serializeOutput(details).text }],
|
|
79
|
+
details,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function sumUsage(results: readonly AgentToolResult<unknown>[]): Usage | undefined {
|
|
84
|
+
const usages = results.flatMap(({ usage }) => usage ? [usage] : []);
|
|
85
|
+
if (usages.length === 0) return undefined;
|
|
86
|
+
return usages.reduce<Usage>((total, usage) => ({
|
|
87
|
+
input: total.input + usage.input,
|
|
88
|
+
output: total.output + usage.output,
|
|
89
|
+
cacheRead: total.cacheRead + usage.cacheRead,
|
|
90
|
+
cacheWrite: total.cacheWrite + usage.cacheWrite,
|
|
91
|
+
...(total.cacheWrite1h === undefined && usage.cacheWrite1h === undefined
|
|
92
|
+
? {}
|
|
93
|
+
: { cacheWrite1h: (total.cacheWrite1h ?? 0) + (usage.cacheWrite1h ?? 0) }),
|
|
94
|
+
...(total.reasoning === undefined && usage.reasoning === undefined
|
|
95
|
+
? {}
|
|
96
|
+
: { reasoning: (total.reasoning ?? 0) + (usage.reasoning ?? 0) }),
|
|
97
|
+
totalTokens: total.totalTokens + usage.totalTokens,
|
|
98
|
+
cost: {
|
|
99
|
+
input: total.cost.input + usage.cost.input,
|
|
100
|
+
output: total.cost.output + usage.cost.output,
|
|
101
|
+
cacheRead: total.cost.cacheRead + usage.cost.cacheRead,
|
|
102
|
+
cacheWrite: total.cost.cacheWrite + usage.cost.cacheWrite,
|
|
103
|
+
total: total.cost.total + usage.cost.total,
|
|
104
|
+
},
|
|
105
|
+
}), {
|
|
106
|
+
input: 0,
|
|
107
|
+
output: 0,
|
|
108
|
+
cacheRead: 0,
|
|
109
|
+
cacheWrite: 0,
|
|
110
|
+
totalTokens: 0,
|
|
111
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function codeExecutionResult(
|
|
116
|
+
details: unknown,
|
|
117
|
+
innerResults: readonly AgentToolResult<unknown>[],
|
|
118
|
+
): AgentToolResult<unknown> {
|
|
119
|
+
const addedToolNames = [...new Set(
|
|
120
|
+
innerResults.flatMap(({ addedToolNames }) => addedToolNames ?? []),
|
|
121
|
+
)].sort();
|
|
122
|
+
const usage = sumUsage(innerResults);
|
|
123
|
+
return {
|
|
124
|
+
...result(details),
|
|
125
|
+
...(addedToolNames.length > 0 ? { addedToolNames } : {}),
|
|
126
|
+
...(usage ? { usage } : {}),
|
|
127
|
+
...(innerResults.length > 0 && innerResults.every(({ terminate }) => terminate === true)
|
|
128
|
+
? { terminate: true }
|
|
129
|
+
: {}),
|
|
130
|
+
};
|
|
55
131
|
}
|
|
56
132
|
|
|
57
133
|
// 上游把 Code Mode 类工具交付为 AI SDK tool;本仓只取 description 和 execute 两件,
|
|
@@ -59,6 +135,7 @@ function codeExecutionTools(tools: ToolRegistry): ToolSet {
|
|
|
59
135
|
function toCodeExecutionPort(
|
|
60
136
|
tool: ToolSet[string],
|
|
61
137
|
name: string,
|
|
138
|
+
project: (details: unknown) => AgentToolResult<unknown> = result,
|
|
62
139
|
): RuntimeCodeExecutionPort {
|
|
63
140
|
const { description, execute } = tool;
|
|
64
141
|
if (typeof description !== "string" || description.length === 0) {
|
|
@@ -69,7 +146,7 @@ function toCodeExecutionPort(
|
|
|
69
146
|
}
|
|
70
147
|
return {
|
|
71
148
|
description,
|
|
72
|
-
execute: (input) =>
|
|
149
|
+
execute: async (input) => project(await execute(input, {
|
|
73
150
|
toolCallId: name,
|
|
74
151
|
messages: [],
|
|
75
152
|
context: undefined,
|
|
@@ -171,26 +248,33 @@ export function createWorkspaceCodeExecutionFactory(options: {
|
|
|
171
248
|
readonly workspace: WorkspacePort;
|
|
172
249
|
}): RuntimeCodeExecutionFactory {
|
|
173
250
|
return {
|
|
174
|
-
create(
|
|
175
|
-
const
|
|
176
|
-
ctx: options.ctx,
|
|
177
|
-
loader: options.loader,
|
|
178
|
-
globalOutbound: options.outbound,
|
|
179
|
-
tools: codeExecutionTools(tools),
|
|
180
|
-
// 先于外层 60s 截止结束,给 Runtime RPC 结算和 Worker 释放留出时间。
|
|
181
|
-
timeout: CODEMODE_SANDBOX_TIMEOUT_MS,
|
|
182
|
-
state: createWorkspaceStateBackend(
|
|
183
|
-
options.workspace as unknown as WorkspaceFsLike,
|
|
184
|
-
),
|
|
185
|
-
name: "execute",
|
|
186
|
-
});
|
|
187
|
-
const port = toCodeExecutionPort(tool, "execute");
|
|
251
|
+
create(candidates) {
|
|
252
|
+
const description = codeExecutionDescription(candidates);
|
|
188
253
|
return {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
254
|
+
description,
|
|
255
|
+
async execute(input) {
|
|
256
|
+
const innerResults: AgentToolResult<unknown>[] = [];
|
|
257
|
+
const { tool } = createExecuteRuntime({
|
|
258
|
+
ctx: options.ctx,
|
|
259
|
+
loader: options.loader,
|
|
260
|
+
globalOutbound: options.outbound,
|
|
261
|
+
tools: piCandidatesToAiTools(candidates, {
|
|
262
|
+
onResult: (value) => innerResults.push(value),
|
|
263
|
+
}),
|
|
264
|
+
description,
|
|
265
|
+
// 先于外层 60s 截止结束,给 Runtime RPC 结算和 Worker 释放留出时间。
|
|
266
|
+
timeout: CODEMODE_SANDBOX_TIMEOUT_MS,
|
|
267
|
+
state: createWorkspaceStateBackend(
|
|
268
|
+
options.workspace as unknown as WorkspaceFsLike,
|
|
269
|
+
),
|
|
270
|
+
name: "execute",
|
|
271
|
+
});
|
|
272
|
+
return toCodeExecutionPort(
|
|
273
|
+
tool,
|
|
274
|
+
"execute",
|
|
275
|
+
(details) => codeExecutionResult(details, innerResults),
|
|
276
|
+
).execute(input);
|
|
277
|
+
},
|
|
194
278
|
};
|
|
195
279
|
},
|
|
196
280
|
};
|
package/src/pi/tool/core.ts
CHANGED
|
@@ -219,7 +219,8 @@ const CODEMODE_EXECUTE_TIMEOUT_MS = 60_000;
|
|
|
219
219
|
function runCodemode(
|
|
220
220
|
runtime: RuntimeCodeExecutionPort,
|
|
221
221
|
label: string,
|
|
222
|
-
project: (
|
|
222
|
+
project: (result: AgentToolResult<unknown>) => AgentToolResult<unknown> =
|
|
223
|
+
(result) => result,
|
|
223
224
|
): AgentTool<typeof executeParameters>["execute"] {
|
|
224
225
|
return async (_toolCallId, input, signal) => {
|
|
225
226
|
signal?.throwIfAborted();
|
|
@@ -245,7 +246,7 @@ function runCodemode(
|
|
|
245
246
|
try {
|
|
246
247
|
return project(await Promise.race([
|
|
247
248
|
runtime.execute(input),
|
|
248
|
-
deadline,
|
|
249
|
+
deadline.then(result),
|
|
249
250
|
]));
|
|
250
251
|
} finally {
|
|
251
252
|
if (timeout !== undefined) clearTimeout(timeout);
|
|
@@ -303,7 +304,11 @@ export function browserExecutionPiToolCandidate(
|
|
|
303
304
|
label: "Drive a browser",
|
|
304
305
|
description: runtime.description,
|
|
305
306
|
parameters: executeParameters,
|
|
306
|
-
execute: runCodemode(
|
|
307
|
+
execute: runCodemode(
|
|
308
|
+
runtime,
|
|
309
|
+
"Browser Code Mode execute",
|
|
310
|
+
({ details }) => browserResult(details),
|
|
311
|
+
),
|
|
307
312
|
};
|
|
308
313
|
return {
|
|
309
314
|
owner: "core:browser",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
2
|
+
import { validateToolArguments } from "@earendil-works/pi-ai";
|
|
3
|
+
import { jsonSchema, tool as aiTool, type ToolSet } from "ai";
|
|
4
|
+
import type { PiToolCandidate } from "./compiler";
|
|
5
|
+
|
|
6
|
+
interface NestedToolOptions {
|
|
7
|
+
readonly fallbackToolCallId?: (name: string) => string;
|
|
8
|
+
readonly onResult?: (result: AgentToolResult<unknown>) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** The one Pi candidate to AI SDK ToolSet adapter used by nested runtimes. */
|
|
12
|
+
export function piCandidatesToAiTools(
|
|
13
|
+
candidates: readonly PiToolCandidate[],
|
|
14
|
+
options: NestedToolOptions,
|
|
15
|
+
): ToolSet {
|
|
16
|
+
return Object.fromEntries(candidates.map((candidate) => [
|
|
17
|
+
candidate.tool.name,
|
|
18
|
+
aiTool({
|
|
19
|
+
description: candidate.tool.description,
|
|
20
|
+
inputSchema: jsonSchema(candidate.tool.parameters as never),
|
|
21
|
+
execute: async (input, call) => {
|
|
22
|
+
const toolCallId = call?.toolCallId ??
|
|
23
|
+
options.fallbackToolCallId?.(candidate.tool.name) ??
|
|
24
|
+
candidate.tool.name;
|
|
25
|
+
const prepared = candidate.tool.prepareArguments?.(input) ?? input;
|
|
26
|
+
const args = validateToolArguments(candidate.tool, {
|
|
27
|
+
type: "toolCall",
|
|
28
|
+
id: toolCallId,
|
|
29
|
+
name: candidate.tool.name,
|
|
30
|
+
arguments: prepared as Record<string, unknown>,
|
|
31
|
+
});
|
|
32
|
+
const result = await candidate.tool.execute(
|
|
33
|
+
toolCallId,
|
|
34
|
+
args,
|
|
35
|
+
call?.abortSignal ?? new AbortController().signal,
|
|
36
|
+
);
|
|
37
|
+
options.onResult?.(result);
|
|
38
|
+
return result;
|
|
39
|
+
},
|
|
40
|
+
}),
|
|
41
|
+
]));
|
|
42
|
+
}
|
package/src/pi/tool/schedule.ts
CHANGED
|
@@ -10,10 +10,6 @@ import type {
|
|
|
10
10
|
import type { ScheduleSpec } from "../../kernel/receipts";
|
|
11
11
|
import { serializeOutput } from "../../lib/artifacts";
|
|
12
12
|
import type { PiToolCandidate } from "./compiler";
|
|
13
|
-
import {
|
|
14
|
-
toolRegistryFromPiCandidates,
|
|
15
|
-
type ToolRegistry,
|
|
16
|
-
} from "../../tool-registry";
|
|
17
13
|
|
|
18
14
|
const scheduleTriggerParameters = Type.Union([
|
|
19
15
|
Type.Object({
|
|
@@ -259,8 +255,3 @@ export function schedulePiToolCandidates(
|
|
|
259
255
|
}
|
|
260
256
|
|
|
261
257
|
/** 从 {@link RuntimeSchedulePort} 生成定时任务 Tool 集。 */
|
|
262
|
-
export function createScheduleTools(
|
|
263
|
-
schedule: RuntimeSchedulePort,
|
|
264
|
-
): ToolRegistry {
|
|
265
|
-
return toolRegistryFromPiCandidates(schedulePiToolCandidates(schedule));
|
|
266
|
-
}
|
package/src/pi/tool/skill.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
type SkillScriptRunner,
|
|
7
7
|
type SkillSource,
|
|
8
8
|
} from "agents/skills";
|
|
9
|
-
import {
|
|
9
|
+
import { tool } from "ai";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import type {
|
|
12
12
|
RuntimeSkillScriptPolicy,
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
} from "../../kernel/bindings";
|
|
15
15
|
import { aiToolToPi } from "./ai-adapter";
|
|
16
16
|
import type { PiToolCandidate } from "./compiler";
|
|
17
|
+
import { piCandidatesToAiTools } from "./nested-tools";
|
|
17
18
|
import { serializeWorkspaceMutation } from "./workspace-sandbox";
|
|
18
19
|
|
|
19
20
|
/** A configured Skill source and its script capabilities. */
|
|
@@ -31,25 +32,6 @@ export interface SkillPiToolOptions {
|
|
|
31
32
|
readonly tools?: readonly PiToolCandidate[];
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
function scriptTools(
|
|
35
|
-
candidates: readonly PiToolCandidate[],
|
|
36
|
-
names: readonly string[],
|
|
37
|
-
): ToolSet {
|
|
38
|
-
const byName = new Map(
|
|
39
|
-
candidates.map((candidate) => [candidate.tool.name, candidate.tool]),
|
|
40
|
-
);
|
|
41
|
-
return Object.fromEntries(names.flatMap((name) => {
|
|
42
|
-
const candidate = byName.get(name);
|
|
43
|
-
if (!candidate) return [];
|
|
44
|
-
return [[name, {
|
|
45
|
-
description: candidate.description,
|
|
46
|
-
inputSchema: jsonSchema(candidate.parameters as never),
|
|
47
|
-
execute: async (input: unknown) =>
|
|
48
|
-
(await candidate.execute(`skill-script:${name}`, input)).details,
|
|
49
|
-
}]];
|
|
50
|
-
})) as ToolSet;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
35
|
/**
|
|
54
36
|
* `run_skill_script` 一次挂载的 Skill 资源总量上限。
|
|
55
37
|
*
|
|
@@ -166,6 +148,10 @@ function scriptRunner(
|
|
|
166
148
|
const workspace = policy.workspace !== "none" && options.workspace
|
|
167
149
|
? policy.workspace
|
|
168
150
|
: "none";
|
|
151
|
+
let toolCallOrdinal = 0;
|
|
152
|
+
const selected = (options.tools ?? []).filter(({ tool }) =>
|
|
153
|
+
policy.tools.includes(tool.name)
|
|
154
|
+
);
|
|
169
155
|
return createSkillScriptRunner({
|
|
170
156
|
loader: options.loader!,
|
|
171
157
|
network: policy.network === "full",
|
|
@@ -173,7 +159,10 @@ function scriptRunner(
|
|
|
173
159
|
...(workspace !== "none" && options.workspace
|
|
174
160
|
? { workspaceInstance: options.workspace }
|
|
175
161
|
: {}),
|
|
176
|
-
tools:
|
|
162
|
+
tools: piCandidatesToAiTools(selected, {
|
|
163
|
+
fallbackToolCallId: (name) =>
|
|
164
|
+
`skill-script:${++toolCallOrdinal}:${name}`,
|
|
165
|
+
}),
|
|
177
166
|
}).run(request);
|
|
178
167
|
},
|
|
179
168
|
};
|
package/src/pi/tool/subagent.ts
CHANGED
|
@@ -13,10 +13,6 @@ import {
|
|
|
13
13
|
subagentTerminalStatus,
|
|
14
14
|
} from "../../kernel/subagent-runtime";
|
|
15
15
|
import type { PiToolCandidate } from "./compiler";
|
|
16
|
-
import {
|
|
17
|
-
toolRegistryFromPiCandidates,
|
|
18
|
-
type ToolRegistry,
|
|
19
|
-
} from "../../tool-registry";
|
|
20
16
|
|
|
21
17
|
const BACKGROUND_MAX_BUDGET_MS = 10 * 60 * 1_000;
|
|
22
18
|
|
|
@@ -275,12 +271,3 @@ export function subagentPiToolCandidates(
|
|
|
275
271
|
}
|
|
276
272
|
|
|
277
273
|
/** 从 {@link RuntimeSubagentPort} 生成已启用 SubAgent Tool 集。 */
|
|
278
|
-
export function createSubagentTools(
|
|
279
|
-
subagents: RuntimeSubagentPort | undefined,
|
|
280
|
-
enabledSubagents: readonly string[],
|
|
281
|
-
lifecycle?: RuntimeSubagentLifecyclePort,
|
|
282
|
-
): ToolRegistry {
|
|
283
|
-
return toolRegistryFromPiCandidates(
|
|
284
|
-
subagentPiToolCandidates(subagents, enabledSubagents, lifecycle),
|
|
285
|
-
);
|
|
286
|
-
}
|
|
@@ -2,10 +2,6 @@ import type { AgentTool, AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
|
2
2
|
import { Type } from "@earendil-works/pi-ai";
|
|
3
3
|
import type { WorkspaceRevisionRestorePort } from "../../workspace-versioning";
|
|
4
4
|
import { serializeOutput } from "../../lib/artifacts";
|
|
5
|
-
import {
|
|
6
|
-
toolRegistryFromPiCandidates,
|
|
7
|
-
type ToolRegistry,
|
|
8
|
-
} from "../../tool-registry";
|
|
9
5
|
import type { PiToolCandidate } from "./compiler";
|
|
10
6
|
|
|
11
7
|
const parameters = Type.Object({
|
|
@@ -54,11 +50,3 @@ export function workspaceRevisionPiToolCandidate(
|
|
|
54
50
|
summary: "Restore the Workspace tree",
|
|
55
51
|
};
|
|
56
52
|
}
|
|
57
|
-
|
|
58
|
-
export function createWorkspaceRevisionTools(
|
|
59
|
-
versions: WorkspaceRevisionRestorePort,
|
|
60
|
-
): ToolRegistry {
|
|
61
|
-
return toolRegistryFromPiCandidates([
|
|
62
|
-
workspaceRevisionPiToolCandidate(versions),
|
|
63
|
-
]);
|
|
64
|
-
}
|
|
@@ -21,10 +21,6 @@ import type {
|
|
|
21
21
|
import { serializeOutput } from "../../lib/artifacts";
|
|
22
22
|
import { aiToolToPi } from "./ai-adapter";
|
|
23
23
|
import type { PiToolCandidate } from "./compiler";
|
|
24
|
-
import {
|
|
25
|
-
toolRegistryFromPiCandidates,
|
|
26
|
-
type ToolRegistry,
|
|
27
|
-
} from "../../tool-registry";
|
|
28
24
|
|
|
29
25
|
// #region Shared Pi result helpers
|
|
30
26
|
|
|
@@ -428,9 +424,6 @@ export function workspacePiToolCandidates(
|
|
|
428
424
|
}
|
|
429
425
|
|
|
430
426
|
/** 从 {@link WorkspacePort} 生成标准 workspace 文件 Tool 集(read / write / edit …)。 */
|
|
431
|
-
export function createWorkspaceTools(workspace: WorkspacePort): ToolRegistry {
|
|
432
|
-
return toolRegistryFromPiCandidates(workspacePiToolCandidates(workspace));
|
|
433
|
-
}
|
|
434
427
|
|
|
435
428
|
// #endregion
|
|
436
429
|
|
|
@@ -625,8 +618,5 @@ export function sandboxPiToolCandidates(
|
|
|
625
618
|
}
|
|
626
619
|
|
|
627
620
|
/** 从 {@link RuntimeSandboxPort} 生成 Sandbox Tool 集。 */
|
|
628
|
-
export function createSandboxTools(sandbox: RuntimeSandboxPort): ToolRegistry {
|
|
629
|
-
return toolRegistryFromPiCandidates(sandboxPiToolCandidates(sandbox));
|
|
630
|
-
}
|
|
631
621
|
|
|
632
622
|
// #endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ToolResultMessage } from "@earendil-works/pi-ai";
|
|
2
|
+
import { isEqual } from "lodash-es";
|
|
2
3
|
import { EXECUTION_LEVELS } from "../../lib/execution-level";
|
|
3
4
|
import {
|
|
4
5
|
decidePiToolApproval,
|
|
@@ -444,11 +445,10 @@ function sameToolInput(
|
|
|
444
445
|
{ type: "tool-input" }
|
|
445
446
|
>,
|
|
446
447
|
): boolean {
|
|
447
|
-
// 待确认:JSON.stringify 对对象键顺序敏感;当前写入链会保留输入顺序,重建输入的调用方可能产生语义相同但顺序不同的对象。
|
|
448
448
|
return (
|
|
449
449
|
previous.toolName === milestone.toolName &&
|
|
450
450
|
previous.retry === milestone.retry &&
|
|
451
|
-
|
|
451
|
+
isEqual(previous.input, milestone.input)
|
|
452
452
|
);
|
|
453
453
|
}
|
|
454
454
|
|
package/src/runtime-agent.ts
CHANGED
|
@@ -36,12 +36,8 @@ import {
|
|
|
36
36
|
import type {
|
|
37
37
|
ResolvedResources,
|
|
38
38
|
RuntimeAgentHooks,
|
|
39
|
+
ToolAssemblyResult,
|
|
39
40
|
} from "./runtime-definition";
|
|
40
|
-
import {
|
|
41
|
-
normalizeToolAssembly,
|
|
42
|
-
type ToolAssemblyResult,
|
|
43
|
-
type ToolRegistry,
|
|
44
|
-
} from "./tool-registry";
|
|
45
41
|
import type { RuntimeAssemblyView } from "./kernel/runtime-assembly-view";
|
|
46
42
|
import type { RuntimeConfigUpdateResult } from "./kernel/runtime-config";
|
|
47
43
|
import {
|
|
@@ -108,7 +104,7 @@ interface RuntimeAgentDefinitionBase<
|
|
|
108
104
|
readonly tools: (
|
|
109
105
|
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
110
106
|
config: Config,
|
|
111
|
-
) =>
|
|
107
|
+
) => ToolAssemblyResult | Promise<ToolAssemblyResult>;
|
|
112
108
|
|
|
113
109
|
readonly hooks?:
|
|
114
110
|
| RuntimeAgentHooks<Env, Config, Command, Change>
|
|
@@ -628,16 +624,16 @@ export function defineRuntimeAgent<
|
|
|
628
624
|
const context = this.createDefinitionContext({
|
|
629
625
|
value: loaded.config,
|
|
630
626
|
});
|
|
631
|
-
let tools =
|
|
627
|
+
let tools = await withRuntimeLoadTimeout(
|
|
632
628
|
"definition.tools",
|
|
633
629
|
() => (
|
|
634
630
|
definition.tools as (
|
|
635
631
|
context: RuntimeAgentPlanningContext<Env, Command, Change>,
|
|
636
632
|
config: Config,
|
|
637
|
-
) =>
|
|
633
|
+
) => ToolAssemblyResult | Promise<ToolAssemblyResult>
|
|
638
634
|
)(context, loaded.config),
|
|
639
635
|
{ timeoutMs: RUNTIME_LOAD_TIMEOUT_MS },
|
|
640
|
-
)
|
|
636
|
+
);
|
|
641
637
|
let hooks = resolveDefinitionHooks(context);
|
|
642
638
|
if (!this.telemetryResolved) {
|
|
643
639
|
this.resolvedTelemetry = resolveDefinitionTelemetry(context);
|