@springbrand/agent-runtime 0.2.0-alpha.72 → 0.3.0-alpha.1
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 -3
- package/src/{agent-tool-runtime.ts → adapter/cloudflare/agent-tool.ts} +1 -1
- package/src/adapter/cloudflare/agent.ts +1539 -0
- package/src/{db/index.ts → adapter/cloudflare/database.ts} +18 -55
- package/src/{runtime-agent.ts → adapter/cloudflare/define-agent.ts} +25 -35
- package/src/adapter/cloudflare/dynamic-worker-observability.ts +1 -1
- package/src/adapter/cloudflare/resources/runtime-resources.ts +4 -4
- package/src/adapter/cloudflare/sandbox/adapter.ts +1 -1
- package/src/{db → adapter/cloudflare}/schema.ts +16 -83
- package/src/adapter/cloudflare/subagent/definition.ts +63 -33
- package/src/adapter/cloudflare/subagent/runner.ts +174 -120
- package/src/adapter/cloudflare/subagent/tools.ts +13 -14
- package/src/adapter/cloudflare/universal-agent/preparation.ts +7 -7
- package/src/adapter/cloudflare/universal-agent/tools.ts +10 -10
- package/src/adapter/cloudflare/workspace/git-fs.ts +1 -1
- package/src/adapter/cloudflare/workspace/scoped-workspace.ts +1 -1
- package/src/adapter/cloudflare/workspace/version-control.ts +2 -2
- package/src/config/activation.ts +140 -0
- package/src/{runtime-agent-context.ts → config/agent-context.ts} +3 -3
- package/src/{runtime-assembler.ts → config/assembler.ts} +20 -19
- package/src/{kernel/runtime-assembly.ts → config/assembly-projection.ts} +4 -4
- package/src/{pi/assembly/snapshot.ts → config/assembly-snapshot.ts} +6 -6
- package/src/{runtime-definition.ts → config/definition.ts} +13 -13
- package/src/config/harness-runtime.ts +182 -0
- package/src/config/index.ts +14 -0
- package/src/{pi/runtime-adapter/assembly.ts → config/pinning.ts} +38 -16
- package/src/{kernel/bindings.ts → config/ports.ts} +9 -13
- package/src/{kernel → config}/profile.ts +7 -0
- package/src/{kernel → config}/public-contracts.ts +6 -6
- package/src/{kernel → config}/runtime-load.ts +1 -1
- package/src/{pi/assembly/context.ts → context/assembly.ts} +4 -206
- package/src/{pi/assembly/extensions.ts → context/extension/assembly.ts} +5 -5
- package/src/context/extension/index.ts +3 -0
- package/src/context/index.ts +6 -0
- package/src/{layers/context → context/memory}/budget/gate.ts +2 -2
- package/src/conversation/harness-resume.ts +288 -0
- package/src/conversation/harness-stream.ts +98 -0
- package/src/{pi/runtime-adapter/transcript.ts → conversation/history.ts} +206 -233
- package/src/conversation/index.ts +6 -0
- package/src/{pi → conversation}/message/contract.ts +3 -0
- package/src/{pi → conversation}/message/conversion.ts +75 -0
- package/src/{pi → conversation}/message/index.ts +1 -0
- package/src/{pi → conversation}/message/model-input.ts +1 -1
- package/src/{pi → conversation}/message/projection.ts +76 -10
- package/src/{db/message-ui.repo.ts → conversation/repository.ts} +4 -0
- package/src/conversation/state.ts +175 -0
- package/src/harness/index.ts +7 -0
- package/src/harness/session-harness.ts +481 -0
- package/src/harness/submission-operation.ts +49 -0
- package/src/index.ts +38 -43
- package/src/lib/mcp.ts +1 -1
- package/src/{pi/runtime-adapter/models.ts → models/index.ts} +64 -18
- package/src/{pi/turn/tool-recovery.ts → session/cloudflare/legacy-tool-recovery.ts} +33 -525
- package/src/{pi/session → session/cloudflare}/migration.ts +334 -8
- package/src/{pi/session → session/cloudflare}/storage.ts +8 -36
- package/src/session/index.ts +39 -0
- package/src/submission/admission.ts +275 -0
- package/src/{kernel/receipts.ts → submission/contracts.ts} +14 -0
- package/src/submission/delivery.ts +212 -0
- package/src/submission/finalization.ts +111 -0
- package/src/submission/index.ts +9 -0
- package/src/{kernel/submission-lifecycle.ts → submission/lifecycle.ts} +41 -28
- package/src/{db/submission.repo.ts → submission/repository.ts} +61 -118
- package/src/submission/steer-delivery.ts +167 -0
- package/src/{db/steer.repo.ts → submission/steer-repository.ts} +27 -5
- package/src/telemetry/contract.ts +12 -0
- package/src/telemetry/coordinator.ts +65 -0
- package/src/telemetry/delivery.ts +2 -2
- package/src/telemetry/index.ts +5 -0
- package/src/{model-usage.ts → telemetry/model-usage.ts} +1 -1
- package/src/telemetry/recorder.ts +1 -1
- package/src/telemetry/runtime-telemetry.ts +12 -0
- package/src/{kernel/durable-lifecycle.ts → telemetry/subagent-lifecycle.ts} +1 -1
- package/src/telemetry/turn-events.ts +279 -0
- package/src/{pi/tool → tools}/ai-adapter.ts +2 -2
- package/src/tools/approval/index.ts +1 -0
- package/src/{db/approval.repo.ts → tools/approval/repository.ts} +10 -30
- package/src/{pi/tool → tools}/base.ts +14 -30
- package/src/tools/compiler.ts +327 -0
- package/src/{pi/tool → tools}/core-host.ts +3 -3
- package/src/{pi/tool → tools}/core.ts +3 -3
- package/src/tools/decision-gate.ts +227 -0
- package/src/{pi/tool → tools}/gateway.ts +1 -1
- package/src/tools/human-decisions.ts +127 -0
- package/src/tools/index.ts +30 -0
- package/src/tools/interaction/index.ts +1 -0
- package/src/{pi/tool → tools}/mcp.ts +1 -1
- package/src/{pi/tool → tools}/schedule.ts +3 -3
- package/src/{pi/tool → tools}/skill.ts +4 -4
- package/src/{kernel → tools}/subagent-runtime.ts +1 -1
- package/src/{pi/tool → tools}/subagent.ts +4 -4
- package/src/tools/temporary-agent/approvals.ts +126 -0
- package/src/{layers/orchestration/temporary-agent/core.ts → tools/temporary-agent/coordinator.ts} +41 -49
- package/src/tools/temporary-agent/core.ts +53 -0
- package/src/{layers/orchestration → tools}/temporary-agent/runner.ts +1 -1
- package/src/{layers/orchestration → tools}/temporary-agent/workspace.ts +1 -1
- package/src/{pi/tool → tools}/web-search/api.ts +1 -1
- package/src/{pi/tool → tools}/workspace-revision.ts +2 -2
- package/src/{pi/tool → tools}/workspace-sandbox.ts +2 -2
- package/src/{pi/tool → tools}/workspace-state-connector.ts +1 -1
- package/src/db/milestone.repo.ts +0 -104
- package/src/db/settlement.repo.ts +0 -104
- package/src/kernel/approval-lifecycle.ts +0 -638
- package/src/kernel/interaction-lifecycle.ts +0 -433
- package/src/kernel/recoverable-chat-agent.ts +0 -1020
- package/src/kernel/state.ts +0 -91
- package/src/pi/assembly/index.ts +0 -19
- package/src/pi/runtime-adapter/execution.ts +0 -1163
- package/src/pi/runtime-adapter/index.ts +0 -293
- package/src/pi/runtime-adapter/recovery.ts +0 -982
- package/src/pi/session/index.ts +0 -24
- package/src/pi/tool/compiler.ts +0 -483
- package/src/pi/tool/index.ts +0 -38
- package/src/pi/turn/approval.ts +0 -181
- package/src/pi/turn/index.ts +0 -82
- package/src/pi/turn/interaction.ts +0 -181
- package/src/runtime.ts +0 -4760
- /package/src/{kernel/runtime-assembly-view.ts → config/assembly-view.ts} +0 -0
- /package/src/{kernel → config}/degradation.ts +0 -0
- /package/src/{kernel → config}/runtime-config.ts +0 -0
- /package/src/{kernel/extensions.ts → context/extension/contracts.ts} +0 -0
- /package/src/{db/ext-context.repo.ts → context/extension/repository.ts} +0 -0
- /package/src/{pi/runtime-adapter/openrouter-messages.ts → models/openrouter/messages.ts} +0 -0
- /package/src/{pi/runtime-adapter → models/openrouter}/test-fixtures/openrouter-tool-search.sse +0 -0
- /package/src/{db/submission-admission.repo.ts → submission/admission-repository.ts} +0 -0
- /package/src/{db/telemetry-outbox.repo.ts → telemetry/repository.ts} +0 -0
- /package/src/{db/runtime-event-outbox.repo.ts → telemetry/runtime-event-repository.ts} +0 -0
- /package/src/{pi/tool → tools}/declared.ts +0 -0
- /package/src/{db/interaction.repo.ts → tools/interaction/repository.ts} +0 -0
- /package/src/{pi/tool → tools}/nested-tools.ts +0 -0
- /package/src/{kernel/submission-authority.ts → tools/subagent-authority.ts} +0 -0
- /package/src/{db/agent-tool.repo.ts → tools/subagent-run-repository.ts} +0 -0
- /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/contract.ts +0 -0
- /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/extract/index.ts +0 -0
- /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/fanout/index.ts +0 -0
- /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/registry.ts +0 -0
- /package/src/{pi/tool → tools}/time.ts +0 -0
- /package/src/{pi/tool → tools}/web-fetch.ts +0 -0
- /package/src/{pi/tool → tools}/web-search/index.ts +0 -0
- /package/src/{pi/tool → tools}/web-search/web-search.ts +0 -0
- /package/src/{workspace-versioning.ts → tools/workspace-versioning.ts} +0 -0
package/src/pi/turn/approval.ts
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import type { ToolResultMessage } from "@earendil-works/pi-ai";
|
|
2
|
-
import type {
|
|
3
|
-
ApprovalDecision,
|
|
4
|
-
ApprovalReceipt,
|
|
5
|
-
} from "../../kernel/receipts";
|
|
6
|
-
import { requiresExecutionApproval } from "../../lib/execution-level";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 表示一个 Pi Tool 在执行前等待用户处理的持久审批。
|
|
10
|
-
*
|
|
11
|
-
* Runtime 在 Tool handler 运行前保存它,恢复路径按 `executionId` 读取并应用一次决定。
|
|
12
|
-
*
|
|
13
|
-
* Tool 输入和执行身份随审批一起保存,才能在 Durable Object 重建后恢复原请求,而不是重新推断它。
|
|
14
|
-
*/
|
|
15
|
-
export interface PiToolApproval {
|
|
16
|
-
executionId: string;
|
|
17
|
-
requestId: string;
|
|
18
|
-
source: ApprovalReceipt["source"];
|
|
19
|
-
toolCallId: string;
|
|
20
|
-
toolName: string;
|
|
21
|
-
summary: string;
|
|
22
|
-
executionLevel: ApprovalReceipt["executionLevel"];
|
|
23
|
-
requiredExecutionLevel: ApprovalReceipt["requiredExecutionLevel"];
|
|
24
|
-
inputJson: string;
|
|
25
|
-
createdAt: number;
|
|
26
|
-
status: "pending" | "approved" | "rejected";
|
|
27
|
-
decidedAt?: number;
|
|
28
|
-
reason?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* 描述一次审批转换要求调用方采取的动作。
|
|
33
|
-
*
|
|
34
|
-
* Runtime 根据 `park`、`resume`、`denied` 或 `noop` 决定等待、续跑、写入拒绝结果或忽略重复决定。
|
|
35
|
-
*
|
|
36
|
-
* 状态转换与 I/O 分开,使同一套幂等规则同时服务在线执行和崩溃恢复。
|
|
37
|
-
*/
|
|
38
|
-
export type PiApprovalOutcome =
|
|
39
|
-
| {
|
|
40
|
-
kind: "park";
|
|
41
|
-
executionId: string;
|
|
42
|
-
requestId: string;
|
|
43
|
-
}
|
|
44
|
-
| {
|
|
45
|
-
kind: "resume";
|
|
46
|
-
executionId: string;
|
|
47
|
-
requestId: string;
|
|
48
|
-
toolCallId: string;
|
|
49
|
-
}
|
|
50
|
-
| {
|
|
51
|
-
kind: "denied";
|
|
52
|
-
executionId: string;
|
|
53
|
-
requestId: string;
|
|
54
|
-
toolResult: ToolResultMessage;
|
|
55
|
-
}
|
|
56
|
-
| {
|
|
57
|
-
kind: "noop";
|
|
58
|
-
executionId: string;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* 把审批的新状态和对应动作绑定为一个不可拆分的决策结果。
|
|
63
|
-
*
|
|
64
|
-
* 在线执行与恢复调用方应同时消费 `approval` 和 `outcome`,不要只持久化其中一半。
|
|
65
|
-
*
|
|
66
|
-
* 两者由同一纯函数生成,可避免审批状态已经改变但续跑动作仍按旧状态计算。
|
|
67
|
-
*/
|
|
68
|
-
export interface PiApprovalTransition {
|
|
69
|
-
approval: PiToolApproval;
|
|
70
|
-
outcome: PiApprovalOutcome;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* 判断当前 Pi Tool 是否必须先等待用户审批。
|
|
75
|
-
*
|
|
76
|
-
* 执行适配器会在调用 Tool handler 前传入 Agent 已授予档位和 Tool 所需档位。
|
|
77
|
-
*
|
|
78
|
-
* 最终矩阵委托给共享的 `requiresExecutionApproval`,避免 Pi 路径复制后偏离 Runtime 规则。
|
|
79
|
-
*/
|
|
80
|
-
export function requiresPiToolApproval(input: {
|
|
81
|
-
executionLevel: ApprovalReceipt["executionLevel"];
|
|
82
|
-
requiredExecutionLevel: ApprovalReceipt["requiredExecutionLevel"];
|
|
83
|
-
}): boolean {
|
|
84
|
-
return requiresExecutionApproval(
|
|
85
|
-
input.executionLevel,
|
|
86
|
-
input.requiredExecutionLevel,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 创建一个待处理审批,并告诉调用方暂停当前 Turn。
|
|
92
|
-
*
|
|
93
|
-
* 执行适配器确认需要审批后调用它,再把返回的 `approval` 持久化并等待用户决定。
|
|
94
|
-
*
|
|
95
|
-
* 此处不填写决定时间或理由,保证新记录只有一个明确的 `pending` 起点。
|
|
96
|
-
*/
|
|
97
|
-
export function parkPiToolApproval(
|
|
98
|
-
input: Omit<
|
|
99
|
-
PiToolApproval,
|
|
100
|
-
"status" | "decidedAt" | "reason"
|
|
101
|
-
>,
|
|
102
|
-
): PiApprovalTransition {
|
|
103
|
-
return {
|
|
104
|
-
approval: { ...input, status: "pending" },
|
|
105
|
-
outcome: {
|
|
106
|
-
kind: "park",
|
|
107
|
-
executionId: input.executionId,
|
|
108
|
-
requestId: input.requestId,
|
|
109
|
-
},
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 把用户的首次审批决定应用到待处理记录。
|
|
115
|
-
*
|
|
116
|
-
* 在线审批和恢复路径在读到持久审批后调用它;已经决定过的记录会返回 `noop`,调用方不得再次执行 Tool。
|
|
117
|
-
*
|
|
118
|
-
* 拒绝仍生成 `isError: false` 的稳定 ToolResult,这是现有客户端识别 rejection envelope 的协议,不能改成普通异常。
|
|
119
|
-
*/
|
|
120
|
-
export function decidePiToolApproval(
|
|
121
|
-
approval: PiToolApproval,
|
|
122
|
-
input: ApprovalDecision & { decidedAt: number },
|
|
123
|
-
): PiApprovalTransition {
|
|
124
|
-
// 已结束的审批保持原状态,重复或并发决定只能得到 noop。
|
|
125
|
-
// 恢复路径依赖这一点避免重复续跑或产生相反终态。
|
|
126
|
-
if (approval.status !== "pending") {
|
|
127
|
-
return {
|
|
128
|
-
approval,
|
|
129
|
-
outcome: {
|
|
130
|
-
kind: "noop",
|
|
131
|
-
executionId: approval.executionId,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (input.decision !== "deny") {
|
|
137
|
-
return {
|
|
138
|
-
approval: {
|
|
139
|
-
...approval,
|
|
140
|
-
status: "approved",
|
|
141
|
-
decidedAt: input.decidedAt,
|
|
142
|
-
},
|
|
143
|
-
outcome: {
|
|
144
|
-
kind: "resume",
|
|
145
|
-
executionId: approval.executionId,
|
|
146
|
-
requestId: approval.requestId,
|
|
147
|
-
toolCallId: approval.toolCallId,
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const reason = input.reason?.trim() || "Tool execution denied by user";
|
|
153
|
-
// 拒绝是一个已处理的 Tool 结果,不是 Tool handler 失败。
|
|
154
|
-
// 保留 rejection details 和 isError:false,客户端才能继续显示既有拒绝语义。
|
|
155
|
-
return {
|
|
156
|
-
approval: {
|
|
157
|
-
...approval,
|
|
158
|
-
status: "rejected",
|
|
159
|
-
decidedAt: input.decidedAt,
|
|
160
|
-
reason,
|
|
161
|
-
},
|
|
162
|
-
outcome: {
|
|
163
|
-
kind: "denied",
|
|
164
|
-
executionId: approval.executionId,
|
|
165
|
-
requestId: approval.requestId,
|
|
166
|
-
toolResult: {
|
|
167
|
-
role: "toolResult",
|
|
168
|
-
toolCallId: approval.toolCallId,
|
|
169
|
-
toolName: approval.toolName,
|
|
170
|
-
content: [{ type: "text", text: reason }],
|
|
171
|
-
details: {
|
|
172
|
-
status: "rejected",
|
|
173
|
-
executionId: approval.executionId,
|
|
174
|
-
reason,
|
|
175
|
-
},
|
|
176
|
-
isError: false,
|
|
177
|
-
timestamp: input.decidedAt,
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
}
|
package/src/pi/turn/index.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 集中导出 Pi Turn 的审批和崩溃恢复规则。
|
|
3
|
-
*
|
|
4
|
-
* @remarks
|
|
5
|
-
* Runtime 适配器通过本入口判断审批、重放持久记录并选择恢复动作。
|
|
6
|
-
*
|
|
7
|
-
* 本目录统一使用以下术语:
|
|
8
|
-
*
|
|
9
|
-
* - **审批(approval)**:Tool handler 运行前持久化的用户许可;`pending` 状态会暂停 Turn。
|
|
10
|
-
* - **交互(interaction)**:结果由客户端投递而非 `execute()` 产出的 Tool 调用;`pending` 状态同样暂停 Turn。
|
|
11
|
-
* 与审批的差别只在响应体:审批是三态枚举,交互是任意 JSON。
|
|
12
|
-
* - **里程碑(milestone)**:属于同一个 `turnId` 和 `assemblyRevision` 的持久 JSON 记录。
|
|
13
|
-
* - **结算结果(settled ToolResult)**:已持久化且恢复时必须复用、不能再次执行副作用的 Tool 结果。
|
|
14
|
-
* - **续跑(continuation)**:审批或 Tool 结算后恢复原 Turn 的动作;先记 `pending`,再记 `committed`。
|
|
15
|
-
* - **权威结果(canonical ToolResult)**:同一 `toolCallId` 第一次成功重放出的结算结果。
|
|
16
|
-
*
|
|
17
|
-
* 这些定义对应 Runtime 的持久记录和恢复状态机;其他文件应引用本入口,不要另写一套含义。
|
|
18
|
-
*
|
|
19
|
-
* @packageDocumentation
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import {
|
|
23
|
-
parkPiToolApproval,
|
|
24
|
-
requiresPiToolApproval,
|
|
25
|
-
} from "./approval";
|
|
26
|
-
import { parkPiToolInteraction } from "./interaction";
|
|
27
|
-
import {
|
|
28
|
-
applyRecoveredPiApprovalDecision,
|
|
29
|
-
applyRecoveredPiToolInteractionSettlement,
|
|
30
|
-
commitPiRecoveryContinuation,
|
|
31
|
-
encodePiToolRecoveryMilestone,
|
|
32
|
-
planPiToolRecovery,
|
|
33
|
-
recordRecoveredPiToolInteraction,
|
|
34
|
-
replayPiToolRecovery,
|
|
35
|
-
stagePiAssemblyRepin,
|
|
36
|
-
stagePiRecoveryContinuation,
|
|
37
|
-
} from "./tool-recovery";
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 提供 Pi Tool 审批的两个入口操作。
|
|
41
|
-
*
|
|
42
|
-
* Runtime 执行适配器在调用 Tool handler 前先判断 `requires`,需要等待时再用 `park` 生成待审批状态。
|
|
43
|
-
*
|
|
44
|
-
* 冻结该门面可防止调用方在运行期间替换审批规则;完整类型和决策函数仍由本模块单独导出。
|
|
45
|
-
*/
|
|
46
|
-
export const piApproval = Object.freeze({
|
|
47
|
-
park: parkPiToolApproval,
|
|
48
|
-
requires: requiresPiToolApproval,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 提供 Pi Turn 恢复状态机的稳定入口。
|
|
53
|
-
*
|
|
54
|
-
* Runtime 恢复适配器先用 `replay` 还原状态,再用 `plan` 选择下一步,并按计划写入或提交续跑里程碑。
|
|
55
|
-
*
|
|
56
|
-
* 这些操作保持为无 I/O 的纯决策,持久化和调度仍由 Runtime 负责,避免恢复规则依赖具体存储实现。
|
|
57
|
-
*/
|
|
58
|
-
export const piRecovery = Object.freeze({
|
|
59
|
-
applyApprovalDecision: applyRecoveredPiApprovalDecision,
|
|
60
|
-
applyInteractionSettlement: applyRecoveredPiToolInteractionSettlement,
|
|
61
|
-
commitContinuation: commitPiRecoveryContinuation,
|
|
62
|
-
encodeMilestone: encodePiToolRecoveryMilestone,
|
|
63
|
-
plan: planPiToolRecovery,
|
|
64
|
-
recordInteraction: recordRecoveredPiToolInteraction,
|
|
65
|
-
replay: replayPiToolRecovery,
|
|
66
|
-
stageAssemblyRepin: stagePiAssemblyRepin,
|
|
67
|
-
stageContinuation: stagePiRecoveryContinuation,
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* 提供 Pi Tool interaction(结果由客户端提供的 Tool)的 park 入口。
|
|
72
|
-
*
|
|
73
|
-
* 执行适配器发现 Tool 声明了 `interaction` 后调用 `park` 生成待响应状态;
|
|
74
|
-
* 响应与取消是有状态操作,走 `piRecovery.applyInteractionSettlement`,不放在这个门面里。
|
|
75
|
-
*/
|
|
76
|
-
export const piInteraction = Object.freeze({
|
|
77
|
-
park: parkPiToolInteraction,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
export * from "./approval";
|
|
81
|
-
export * from "./interaction";
|
|
82
|
-
export * from "./tool-recovery";
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import type { ToolResultMessage } from "@earendil-works/pi-ai";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 表示一个 Pi Tool 在等待客户端投递结果时的持久 park 记录。
|
|
5
|
-
*
|
|
6
|
-
* Runtime 在带 `interaction` 声明的 Tool 进入执行链时保存它,恢复路径按 `interactionId` 读取并应用一次响应。
|
|
7
|
-
*
|
|
8
|
-
* Tool 输入随记录一起保存,才能在 Durable Object 重建后把响应映射回原始调用,而不是重新推断它。
|
|
9
|
-
*/
|
|
10
|
-
export interface PiToolInteraction {
|
|
11
|
-
interactionId: string;
|
|
12
|
-
requestId: string;
|
|
13
|
-
toolCallId: string;
|
|
14
|
-
toolName: string;
|
|
15
|
-
inputJson: string;
|
|
16
|
-
createdAt: number;
|
|
17
|
-
status: "pending" | "responded" | "cancelled";
|
|
18
|
-
respondedAt?: number;
|
|
19
|
-
responseJson?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* 说明一次 interaction 为什么在没有拿到用户选择的情况下结束。
|
|
24
|
-
*
|
|
25
|
-
* 目前只有一种:用户没有点选项,而是直接在聊天里发了消息。
|
|
26
|
-
* 新增成员时必须同步更新 `cancelText` 与解码器的枚举校验。
|
|
27
|
-
*/
|
|
28
|
-
export type PiToolInteractionCancelReason =
|
|
29
|
-
| "user_replied_freeform"
|
|
30
|
-
| "submission_terminal";
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* 描述一次 interaction 状态转换要求调用方采取的动作。
|
|
34
|
-
*
|
|
35
|
-
* `park` 表示继续等待,`settle` 表示已得到权威 ToolResult 可以续跑,`noop` 表示重复投递应被忽略。
|
|
36
|
-
*
|
|
37
|
-
* 状态转换与 I/O 分开,使同一套幂等规则同时服务在线执行和崩溃恢复 —— 与审批同构。
|
|
38
|
-
*/
|
|
39
|
-
export type PiToolInteractionOutcome =
|
|
40
|
-
| { kind: "park"; interactionId: string; requestId: string }
|
|
41
|
-
| {
|
|
42
|
-
kind: "settle";
|
|
43
|
-
interactionId: string;
|
|
44
|
-
requestId: string;
|
|
45
|
-
toolCallId: string;
|
|
46
|
-
toolResult: ToolResultMessage;
|
|
47
|
-
}
|
|
48
|
-
| { kind: "noop"; interactionId: string };
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 把 interaction 的新状态和对应动作绑定为一个不可拆分的结果。
|
|
52
|
-
*
|
|
53
|
-
* 在线执行与恢复调用方应同时消费 `interaction` 和 `outcome`,不要只持久化其中一半。
|
|
54
|
-
*/
|
|
55
|
-
export interface PiToolInteractionTransition {
|
|
56
|
-
interaction: PiToolInteraction;
|
|
57
|
-
outcome: PiToolInteractionOutcome;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* 用户改为自由发言时写进 ToolResult 的提示语。
|
|
62
|
-
*
|
|
63
|
-
* 刻意**不包含用户原文** —— 紧随其后的那条用户消息里就有,复制进来模型会读到两遍。
|
|
64
|
-
* 这段文字是模型判断「那句话算不算答案」的唯一依据,改动前先想清楚它会怎么读。
|
|
65
|
-
*/
|
|
66
|
-
const CANCEL_TEXT: Record<PiToolInteractionCancelReason, string> = {
|
|
67
|
-
user_replied_freeform:
|
|
68
|
-
"The user did not pick an option. They replied in the chat instead — " +
|
|
69
|
-
"read their next message and treat it as the answer if it addresses " +
|
|
70
|
-
"the question; otherwise follow whatever they actually asked for.",
|
|
71
|
-
submission_terminal:
|
|
72
|
-
"The turn ended before the user answered. Do not assume any option was chosen.",
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* 创建一条待响应的 interaction,并告诉调用方暂停当前 Tool。
|
|
77
|
-
*
|
|
78
|
-
* 执行适配器确认 Tool 声明了 `interaction` 后调用它,再把返回的记录持久化并等待客户端投递。
|
|
79
|
-
*
|
|
80
|
-
* 此处不填写响应时间或响应体,保证新记录只有一个明确的 `pending` 起点。
|
|
81
|
-
*/
|
|
82
|
-
export function parkPiToolInteraction(
|
|
83
|
-
input: Omit<
|
|
84
|
-
PiToolInteraction,
|
|
85
|
-
"status" | "respondedAt" | "responseJson"
|
|
86
|
-
>,
|
|
87
|
-
): PiToolInteractionTransition {
|
|
88
|
-
return {
|
|
89
|
-
interaction: { ...input, status: "pending" },
|
|
90
|
-
outcome: {
|
|
91
|
-
kind: "park",
|
|
92
|
-
interactionId: input.interactionId,
|
|
93
|
-
requestId: input.requestId,
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* 把客户端的首次响应应用到待响应记录。
|
|
100
|
-
*
|
|
101
|
-
* 在线 RPC 与恢复路径在读到持久记录后调用它;已经结束的记录返回 `noop`,调用方不得再次结算 Tool。
|
|
102
|
-
*
|
|
103
|
-
* `toolResult` 由调用方按 Tool 自己的 `settle` 映射产出 —— 本函数不解释响应体语义,只负责状态单调前进。
|
|
104
|
-
*/
|
|
105
|
-
export function respondPiToolInteraction(
|
|
106
|
-
interaction: PiToolInteraction,
|
|
107
|
-
input: {
|
|
108
|
-
response: unknown;
|
|
109
|
-
toolResult: ToolResultMessage;
|
|
110
|
-
respondedAt: number;
|
|
111
|
-
},
|
|
112
|
-
): PiToolInteractionTransition {
|
|
113
|
-
if (interaction.status !== "pending") {
|
|
114
|
-
return {
|
|
115
|
-
interaction,
|
|
116
|
-
outcome: { kind: "noop", interactionId: interaction.interactionId },
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
return {
|
|
120
|
-
interaction: {
|
|
121
|
-
...interaction,
|
|
122
|
-
status: "responded",
|
|
123
|
-
respondedAt: input.respondedAt,
|
|
124
|
-
responseJson: JSON.stringify(input.response),
|
|
125
|
-
},
|
|
126
|
-
outcome: {
|
|
127
|
-
kind: "settle",
|
|
128
|
-
interactionId: interaction.interactionId,
|
|
129
|
-
requestId: interaction.requestId,
|
|
130
|
-
toolCallId: interaction.toolCallId,
|
|
131
|
-
toolResult: input.toolResult,
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* 在用户没有作答的情况下结束一条 interaction。
|
|
138
|
-
*
|
|
139
|
-
* `dispatchMessage` 发现 park 期间来了用户消息时调用,Submission 进终态收尾时也调用。
|
|
140
|
-
*
|
|
141
|
-
* 取消同样产出 `isError: false` 的稳定 ToolResult —— 它不是 Tool 失败,而是一个「没选」的已处理结果;
|
|
142
|
-
* 改成异常会让模型收到 tool_error 并倾向于重试,那恰恰是我们不想要的。
|
|
143
|
-
*/
|
|
144
|
-
export function cancelPiToolInteraction(
|
|
145
|
-
interaction: PiToolInteraction,
|
|
146
|
-
input: {
|
|
147
|
-
reason: PiToolInteractionCancelReason;
|
|
148
|
-
cancelledAt: number;
|
|
149
|
-
toolResult?: ToolResultMessage;
|
|
150
|
-
},
|
|
151
|
-
): PiToolInteractionTransition {
|
|
152
|
-
if (interaction.status !== "pending") {
|
|
153
|
-
return {
|
|
154
|
-
interaction,
|
|
155
|
-
outcome: { kind: "noop", interactionId: interaction.interactionId },
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
const toolResult: ToolResultMessage = input.toolResult ?? {
|
|
159
|
-
role: "toolResult",
|
|
160
|
-
toolCallId: interaction.toolCallId,
|
|
161
|
-
toolName: interaction.toolName,
|
|
162
|
-
content: [{ type: "text", text: CANCEL_TEXT[input.reason] }],
|
|
163
|
-
details: { cancelled: true, reason: input.reason },
|
|
164
|
-
isError: false,
|
|
165
|
-
timestamp: input.cancelledAt,
|
|
166
|
-
};
|
|
167
|
-
return {
|
|
168
|
-
interaction: {
|
|
169
|
-
...interaction,
|
|
170
|
-
status: "cancelled",
|
|
171
|
-
respondedAt: input.cancelledAt,
|
|
172
|
-
},
|
|
173
|
-
outcome: {
|
|
174
|
-
kind: "settle",
|
|
175
|
-
interactionId: interaction.interactionId,
|
|
176
|
-
requestId: interaction.requestId,
|
|
177
|
-
toolCallId: interaction.toolCallId,
|
|
178
|
-
toolResult,
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
}
|