@springbrand/agent-runtime 0.2.0-alpha.72 → 0.3.0-alpha.2
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 +1592 -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} +62 -119
- 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
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import type { SqlTaggedTemplate } from "agents/chat";
|
|
2
2
|
|
|
3
3
|
import { initializeSchema } from "./schema";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
SubmissionAdmissionRepository,
|
|
6
|
+
SubmissionRepository,
|
|
7
|
+
SteerRepository,
|
|
8
|
+
} from "../../submission";
|
|
9
|
+
import {
|
|
10
|
+
AgentToolRepository,
|
|
11
|
+
ApprovalRepository,
|
|
12
|
+
ToolInteractionRepository,
|
|
13
|
+
} from "../../tools";
|
|
14
|
+
import { ExtContextRepository } from "../../context";
|
|
15
|
+
import { MessageUiRepository } from "../../conversation";
|
|
16
|
+
import {
|
|
17
|
+
RuntimeEventOutboxRepository,
|
|
18
|
+
TelemetryOutboxRepository,
|
|
19
|
+
} from "../../telemetry";
|
|
16
20
|
|
|
17
21
|
// 数据库术语以这里为准。
|
|
18
22
|
// Submission 是一次可持久化的用户提交,从排队到终态都用同一个 submissionId 跟踪。
|
|
19
23
|
// Approval 是某次工具调用的持久化审批记录,executionId 是对外决策时的主键。
|
|
20
24
|
// Tool Interaction 是「结果由客户端提供」的工具调用的 park 记录,interactionId 是主键;
|
|
21
|
-
//
|
|
22
|
-
// Settlement 是工具调用的最终结果,同一 Submission 内用 toolCallId 防止重复落盘。
|
|
23
|
-
// Recovery Milestone 是按 seq 重放的恢复事实,milestoneKey 用来去重。
|
|
25
|
+
// 它保存人的回答,Harness Session 保存工具执行位置和最终 ToolResult。
|
|
24
26
|
// Extension Context 是扩展按 label 保存的文本,不随清空聊天记录删除。
|
|
25
27
|
// Message UI 是会话消息的用户界面补充数据,它由 Transcript 而不是 Turn 生命周期管理。
|
|
26
28
|
// Agent Tool Run 是 Agents SDK 派发的子运行,唯一一张不归 Runtime 所有的表:SDK 建它、写它、清它,
|
|
@@ -28,26 +30,10 @@ import { SubmissionAdmissionRepository } from "./submission-admission.repo";
|
|
|
28
30
|
// 是因为 SDK 没有公开父级侧的「还有没有子运行在跑」读法,而复制一份必然产生第二个真相源。
|
|
29
31
|
// Repository 只把 Runtime 语义翻译成参数化 SQL,所有表都位于当前 Agent 实例自己的 Durable Object SQLite 存储中。
|
|
30
32
|
// Transaction 指 Cloudflare transactionSync 包住的同步操作,回调抛错时整体回滚。
|
|
31
|
-
export * from "./schema";
|
|
32
|
-
export * from "./submission.repo";
|
|
33
|
-
export * from "./approval.repo";
|
|
34
|
-
export * from "./interaction.repo";
|
|
35
|
-
export * from "./settlement.repo";
|
|
36
|
-
export * from "./milestone.repo";
|
|
37
|
-
export * from "./ext-context.repo";
|
|
38
|
-
export * from "./message-ui.repo";
|
|
39
|
-
export * from "./steer.repo";
|
|
40
|
-
export * from "./runtime-event-outbox.repo";
|
|
41
|
-
export * from "./telemetry-outbox.repo";
|
|
42
|
-
export * from "./agent-tool.repo";
|
|
43
|
-
export * from "./submission-admission.repo";
|
|
44
|
-
|
|
45
33
|
export class RuntimeDatabase {
|
|
46
34
|
readonly submissions: SubmissionRepository;
|
|
47
35
|
readonly approvals: ApprovalRepository;
|
|
48
36
|
readonly interactions: ToolInteractionRepository;
|
|
49
|
-
readonly settlements: ToolSettlementRepository;
|
|
50
|
-
readonly milestones: RecoveryMilestoneRepository;
|
|
51
37
|
readonly extContext: ExtContextRepository;
|
|
52
38
|
readonly messageUi: MessageUiRepository;
|
|
53
39
|
readonly steers: SteerRepository;
|
|
@@ -63,11 +49,9 @@ export class RuntimeDatabase {
|
|
|
63
49
|
private readonly sql: SqlTaggedTemplate,
|
|
64
50
|
private readonly transact: <T>(fn: () => T) => T,
|
|
65
51
|
) {
|
|
66
|
-
this.submissions = new SubmissionRepository(sql);
|
|
52
|
+
this.submissions = new SubmissionRepository(sql, transact);
|
|
67
53
|
this.approvals = new ApprovalRepository(sql);
|
|
68
54
|
this.interactions = new ToolInteractionRepository(sql);
|
|
69
|
-
this.settlements = new ToolSettlementRepository(sql);
|
|
70
|
-
this.milestones = new RecoveryMilestoneRepository(sql);
|
|
71
55
|
this.extContext = new ExtContextRepository(sql);
|
|
72
56
|
this.messageUi = new MessageUiRepository(sql);
|
|
73
57
|
this.steers = new SteerRepository(sql);
|
|
@@ -77,25 +61,6 @@ export class RuntimeDatabase {
|
|
|
77
61
|
this.submissionAdmissions = new SubmissionAdmissionRepository(sql);
|
|
78
62
|
}
|
|
79
63
|
|
|
80
|
-
/**
|
|
81
|
-
* 有未完成 Submission,且每一条都停在人机等待上。
|
|
82
|
-
*
|
|
83
|
-
* 换装配的忙碌闸门调用它。「停在等人」有两种形态:待决审批,和等客户端
|
|
84
|
-
* 投递结果的 Tool Interaction —— 两者都意味着没有模型请求在飞、没有工具
|
|
85
|
-
* 在执行,因此换掉能力语义是安全的。
|
|
86
|
-
*
|
|
87
|
-
* 注意它不是「存在待处理的人机等待」:只要有一条 Submission 正在真的执行,
|
|
88
|
-
* 整个判断就必须为假,否则会把执行中的 Turn 切成两套能力语义。
|
|
89
|
-
*/
|
|
90
|
-
everyUnfinishedSubmissionParked(): boolean {
|
|
91
|
-
const unfinished = this.submissions.listUnfinishedIds();
|
|
92
|
-
if (unfinished.length === 0) return false;
|
|
93
|
-
return unfinished.every((submissionId) =>
|
|
94
|
-
this.approvals.listPendingForSubmission(submissionId).length > 0 ||
|
|
95
|
-
this.interactions.listPendingForSubmission(submissionId).length > 0
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
64
|
// 在一个同步 SQLite 事务里运行一组读写。
|
|
100
65
|
// Submission、Approval、Transcript 等需要一起成功或一起回滚时调用,回调不得返回 Promise。
|
|
101
66
|
// 这里直接保留 transactionSync 的抛错回滚语义;待确认:当前泛型签名无法在类型层阻止 async 回调。
|
|
@@ -118,8 +83,6 @@ export class RuntimeDatabase {
|
|
|
118
83
|
this.sql`DELETE FROM pi_submissions`;
|
|
119
84
|
this.sql`DELETE FROM pi_approvals`;
|
|
120
85
|
this.sql`DELETE FROM pi_tool_interactions`;
|
|
121
|
-
this.sql`DELETE FROM pi_tool_settlements`;
|
|
122
|
-
this.sql`DELETE FROM pi_recovery_milestones`;
|
|
123
86
|
this.sql`DELETE FROM pi_telemetry_outbox`;
|
|
124
87
|
}
|
|
125
88
|
}
|
|
@@ -5,53 +5,53 @@ import {
|
|
|
5
5
|
type ChatCapableAgentClass,
|
|
6
6
|
} from "agents";
|
|
7
7
|
import type { UIMessage } from "ai";
|
|
8
|
-
import type { PiCanonicalTranscriptSnapshot } from "
|
|
8
|
+
import type { PiCanonicalTranscriptSnapshot } from "../../conversation";
|
|
9
9
|
import type {
|
|
10
10
|
ApprovalDecision,
|
|
11
11
|
ApprovalReceipt,
|
|
12
12
|
MessageDelivery,
|
|
13
13
|
MessageDispatchReceipt,
|
|
14
14
|
SubmissionReceipt,
|
|
15
|
-
} from "
|
|
16
|
-
import type { RuntimeState } from "
|
|
15
|
+
} from "../../submission";
|
|
16
|
+
import type { RuntimeState } from "../../conversation";
|
|
17
17
|
import type {
|
|
18
18
|
TemporaryAgentApprovalDecision,
|
|
19
19
|
TemporaryAgentApprovalRequest,
|
|
20
20
|
TemporaryAgentLaunch,
|
|
21
|
-
} from "
|
|
22
|
-
import { TEMPORARY_AGENT_LAUNCH_KEY } from "
|
|
21
|
+
} from "../../tools";
|
|
22
|
+
import { TEMPORARY_AGENT_LAUNCH_KEY } from "../../tools";
|
|
23
23
|
import {
|
|
24
24
|
temporaryAgentExtensionIsSafe,
|
|
25
25
|
temporaryAgentToolAllowed,
|
|
26
|
-
} from "
|
|
26
|
+
} from "../../tools";
|
|
27
27
|
import {
|
|
28
28
|
EXECUTION_LEVELS,
|
|
29
29
|
requiresExecutionApproval,
|
|
30
30
|
type ExecutionLevel,
|
|
31
|
-
} from "
|
|
31
|
+
} from "../../lib/execution-level";
|
|
32
32
|
import {
|
|
33
33
|
assembleRuntimeSnapshot,
|
|
34
34
|
type RuntimeCandidate,
|
|
35
|
-
} from "
|
|
35
|
+
} from "../../config";
|
|
36
36
|
import type {
|
|
37
37
|
ResolvedResources,
|
|
38
38
|
ToolAssemblyResult,
|
|
39
|
-
} from "
|
|
40
|
-
import type { RuntimeAssemblyView } from "
|
|
41
|
-
import type { RuntimeConfigUpdateResult } from "
|
|
39
|
+
} from "../../config";
|
|
40
|
+
import type { RuntimeAssemblyView } from "../../config";
|
|
41
|
+
import type { RuntimeConfigUpdateResult } from "../../config";
|
|
42
42
|
import {
|
|
43
43
|
logRuntimeLoadFailure,
|
|
44
44
|
RUNTIME_LOAD_TIMEOUT_MS,
|
|
45
45
|
withRuntimeLoadTimeout,
|
|
46
|
-
} from "
|
|
47
|
-
import { AgentToolRuntimeKernel } from "./agent-tool
|
|
46
|
+
} from "../../config";
|
|
47
|
+
import { AgentToolRuntimeKernel } from "./agent-tool";
|
|
48
48
|
import type {
|
|
49
49
|
RuntimeAgentConfigContext,
|
|
50
50
|
RuntimeAgentPlanningContext,
|
|
51
51
|
RuntimeAgentRole,
|
|
52
52
|
RuntimeAgentToolResult,
|
|
53
|
-
} from "
|
|
54
|
-
import type { AgentTelemetryBinding } from "
|
|
53
|
+
} from "../../config";
|
|
54
|
+
import type { AgentTelemetryBinding } from "../../telemetry";
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* 本文件把应用提供的 Config Definition 与 Planner 接到 Cloudflare Agent 生命周期。
|
|
@@ -70,7 +70,7 @@ export type {
|
|
|
70
70
|
RuntimeAgentRole,
|
|
71
71
|
RuntimeAgentToolResult,
|
|
72
72
|
RuntimeAssemblyContext,
|
|
73
|
-
} from "
|
|
73
|
+
} from "../../config";
|
|
74
74
|
|
|
75
75
|
/** Host 一次性准备的完整 Runtime 加载结果。 */
|
|
76
76
|
export interface LoadedRuntime<Config> {
|
|
@@ -163,15 +163,6 @@ export interface RuntimeAgentControls {
|
|
|
163
163
|
runtimeKey?: string,
|
|
164
164
|
options?: { force?: boolean },
|
|
165
165
|
): Promise<void>;
|
|
166
|
-
/**
|
|
167
|
-
* 确保 Runtime 已加载,再请求 Kernel 刷新当前 Session Context。
|
|
168
|
-
*
|
|
169
|
-
* @remarks
|
|
170
|
-
* 业务侧在外部 Context 变更后调用,例如 Inbox 需要让已存在的聊天立即重读内容。
|
|
171
|
-
*
|
|
172
|
-
* 待确认:当前 `refreshContext` 只检查 Snapshot 已安装,没有重新读取 Context 或刷新缓存。
|
|
173
|
-
*/
|
|
174
|
-
refreshMemoryContext(): Promise<void>;
|
|
175
166
|
/**
|
|
176
167
|
* Read the Runtime Snapshot currently installed on this Session facet.
|
|
177
168
|
*
|
|
@@ -318,7 +309,7 @@ export interface RuntimeAgentConfigControls<Command, Change> {
|
|
|
318
309
|
/** Type-only Host extension seam implemented by AgentRuntimeKernel. */
|
|
319
310
|
declare class RuntimeAgentHostSeam {
|
|
320
311
|
protected prepareToolInteractionResponse(
|
|
321
|
-
input: import("./
|
|
312
|
+
input: import("./agent").ToolInteractionResponsePreparation,
|
|
322
313
|
): Promise<unknown | null>;
|
|
323
314
|
}
|
|
324
315
|
|
|
@@ -449,6 +440,10 @@ export function defineRuntimeAgent<
|
|
|
449
440
|
return this.ensureConfig();
|
|
450
441
|
}
|
|
451
442
|
|
|
443
|
+
protected override ensureRuntimeVersion(runtimeKey: string): Promise<void> {
|
|
444
|
+
return this.ensureConfig(runtimeKey);
|
|
445
|
+
}
|
|
446
|
+
|
|
452
447
|
protected async prepareRuntimeForSubmission(submissionId: string): Promise<void> {
|
|
453
448
|
const beforeSubmission = definition.beforeSubmission as RuntimeAgentDefinitionBase<Env, Config, Command, Change>["beforeSubmission"];
|
|
454
449
|
try {
|
|
@@ -502,14 +497,6 @@ export function defineRuntimeAgent<
|
|
|
502
497
|
}
|
|
503
498
|
}
|
|
504
499
|
|
|
505
|
-
// 作用:确保 Runtime 可用后请求 Kernel 刷新 Session Context。
|
|
506
|
-
// 调用:Inbox 等 RPC 调用方在外部 Context 变更后调用。
|
|
507
|
-
// 待确认:当前 Kernel 的 `refreshContext` 只检查 Snapshot,并未执行实际刷新。
|
|
508
|
-
async refreshMemoryContext(): Promise<void> {
|
|
509
|
-
await this.ensureRuntimeReady();
|
|
510
|
-
await this.refreshContext();
|
|
511
|
-
}
|
|
512
|
-
|
|
513
500
|
async getRuntimeAssembly(): Promise<RuntimeAssemblyView> {
|
|
514
501
|
await this.ensureRuntimeReady();
|
|
515
502
|
return this.readRuntimeAssembly();
|
|
@@ -666,7 +653,10 @@ export function defineRuntimeAgent<
|
|
|
666
653
|
...(telemetry ? { telemetry } : {}),
|
|
667
654
|
});
|
|
668
655
|
|
|
669
|
-
await this.initCandidate(
|
|
656
|
+
await this.initCandidate({
|
|
657
|
+
...candidate,
|
|
658
|
+
runtimeKey: resolvedRuntimeKey,
|
|
659
|
+
});
|
|
670
660
|
this.hasLoadedRuntime = true;
|
|
671
661
|
this.loadedRuntimeKey = resolvedRuntimeKey;
|
|
672
662
|
this.runtimeLoad.complete();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { RuntimeDegradation } from "../../../
|
|
2
|
-
import type { RuntimeExtensionConfig } from "../../../
|
|
3
|
-
import { withRuntimeLoadTimeout } from "../../../
|
|
4
|
-
import type { RuntimeExtensionContribution } from "../../../
|
|
1
|
+
import type { RuntimeDegradation } from "../../../config/degradation";
|
|
2
|
+
import type { RuntimeExtensionConfig } from "../../../context/extension/contracts";
|
|
3
|
+
import { withRuntimeLoadTimeout } from "../../../config/runtime-load";
|
|
4
|
+
import type { RuntimeExtensionContribution } from "../../../config/definition";
|
|
5
5
|
export { createR2SkillSource } from "./r2-skill-source";
|
|
6
6
|
|
|
7
7
|
export interface CloudflareRuntimeExtensionSource {
|
|
@@ -4,8 +4,7 @@ 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
|
|
8
|
-
// 这张表只回答「这次工具调用还等不等得到客户端响应」。
|
|
7
|
+
// pi_tool_interactions 只保存宿主交互事实;Tool 结果由 Pi Session 唯一持久化。
|
|
9
8
|
export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
10
9
|
sql`CREATE TABLE IF NOT EXISTS pi_message_ui (
|
|
11
10
|
message_id TEXT PRIMARY KEY,
|
|
@@ -23,31 +22,21 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
23
22
|
assembly_revision TEXT NOT NULL,
|
|
24
23
|
assembly_descriptor TEXT NOT NULL,
|
|
25
24
|
assistant_message_id TEXT NOT NULL,
|
|
26
|
-
abort_reason TEXT
|
|
27
|
-
recovery_error_count INTEGER NOT NULL DEFAULT 0,
|
|
28
|
-
recovery_reason TEXT,
|
|
29
|
-
context_overflow_retried INTEGER NOT NULL DEFAULT 0
|
|
25
|
+
abort_reason TEXT
|
|
30
26
|
)`;
|
|
31
27
|
const submissionColumns = new Set(
|
|
32
28
|
sql<{ name: string }>`PRAGMA table_info(pi_submissions)`
|
|
33
29
|
.map((column) => column.name),
|
|
34
30
|
);
|
|
31
|
+
if (!submissionColumns.has("runtime_key")) {
|
|
32
|
+
sql`ALTER TABLE pi_submissions ADD COLUMN runtime_key TEXT NOT NULL DEFAULT ''`;
|
|
33
|
+
}
|
|
35
34
|
if (!submissionColumns.has("run_id")) {
|
|
36
35
|
sql`ALTER TABLE pi_submissions ADD COLUMN run_id TEXT`;
|
|
37
36
|
}
|
|
38
37
|
if (!submissionColumns.has("admission_retryable")) {
|
|
39
38
|
sql`ALTER TABLE pi_submissions ADD COLUMN admission_retryable INTEGER`;
|
|
40
39
|
}
|
|
41
|
-
// 跨执行片累计的模型回合数。让步把一个 Turn 切成多片后,每片的回合计数都从 0 开始,
|
|
42
|
-
// 只有把总数落到持久层,全局预算才拦得住「一直让步、永不收敛」的工具循环。
|
|
43
|
-
if (!submissionColumns.has("model_turns")) {
|
|
44
|
-
sql`ALTER TABLE pi_submissions
|
|
45
|
-
ADD COLUMN model_turns INTEGER NOT NULL DEFAULT 0`;
|
|
46
|
-
}
|
|
47
|
-
// 当前让步片的标识。用来丢弃重复到期的续跑 alarm,并让看门狗判断这一轮有没有推进。
|
|
48
|
-
if (!submissionColumns.has("continuation_id")) {
|
|
49
|
-
sql`ALTER TABLE pi_submissions ADD COLUMN continuation_id TEXT`;
|
|
50
|
-
}
|
|
51
40
|
sql`CREATE UNIQUE INDEX IF NOT EXISTS pi_submissions_run_id
|
|
52
41
|
ON pi_submissions(run_id) WHERE run_id IS NOT NULL`;
|
|
53
42
|
if (!submissionColumns.has("queued_input_json")) {
|
|
@@ -62,17 +51,6 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
62
51
|
if (!submissionColumns.has("regenerate_message_id")) {
|
|
63
52
|
sql`ALTER TABLE pi_submissions ADD COLUMN regenerate_message_id TEXT`;
|
|
64
53
|
}
|
|
65
|
-
if (!submissionColumns.has("recovery_error_count")) {
|
|
66
|
-
sql`ALTER TABLE pi_submissions
|
|
67
|
-
ADD COLUMN recovery_error_count INTEGER NOT NULL DEFAULT 0`;
|
|
68
|
-
}
|
|
69
|
-
if (!submissionColumns.has("recovery_reason")) {
|
|
70
|
-
sql`ALTER TABLE pi_submissions ADD COLUMN recovery_reason TEXT`;
|
|
71
|
-
}
|
|
72
|
-
if (!submissionColumns.has("context_overflow_retried")) {
|
|
73
|
-
sql`ALTER TABLE pi_submissions
|
|
74
|
-
ADD COLUMN context_overflow_retried INTEGER NOT NULL DEFAULT 0`;
|
|
75
|
-
}
|
|
76
54
|
sql`CREATE UNIQUE INDEX IF NOT EXISTS pi_submissions_one_running
|
|
77
55
|
ON pi_submissions(status)
|
|
78
56
|
WHERE status = 'running'`;
|
|
@@ -80,20 +58,21 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
80
58
|
steer_id TEXT PRIMARY KEY,
|
|
81
59
|
submission_id TEXT NOT NULL,
|
|
82
60
|
message_id TEXT NOT NULL UNIQUE,
|
|
61
|
+
harness_entry_id TEXT,
|
|
83
62
|
canonical_json TEXT NOT NULL,
|
|
84
63
|
ui_message_json TEXT,
|
|
85
64
|
created_at INTEGER NOT NULL
|
|
86
65
|
)`;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
66
|
+
const steerColumns = new Set(
|
|
67
|
+
sql<{ name: string }>`PRAGMA table_info(pi_pending_steers)`
|
|
68
|
+
.map((column) => column.name),
|
|
69
|
+
);
|
|
70
|
+
if (!steerColumns.has("harness_entry_id")) {
|
|
71
|
+
sql`ALTER TABLE pi_pending_steers ADD COLUMN harness_entry_id TEXT`;
|
|
72
|
+
}
|
|
73
|
+
sql`CREATE UNIQUE INDEX IF NOT EXISTS pi_pending_steers_harness_entry_id
|
|
74
|
+
ON pi_pending_steers(harness_entry_id)
|
|
75
|
+
WHERE harness_entry_id IS NOT NULL`;
|
|
97
76
|
sql`CREATE TABLE IF NOT EXISTS pi_turn_event_outbox (
|
|
98
77
|
event_id TEXT PRIMARY KEY,
|
|
99
78
|
body TEXT NOT NULL,
|
|
@@ -211,52 +190,6 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
211
190
|
responded_at INTEGER,
|
|
212
191
|
UNIQUE (submission_id, tool_call_id)
|
|
213
192
|
)`;
|
|
214
|
-
sql`CREATE TABLE IF NOT EXISTS pi_recovery_milestones (
|
|
215
|
-
submission_id TEXT NOT NULL,
|
|
216
|
-
seq INTEGER NOT NULL,
|
|
217
|
-
milestone_key TEXT NOT NULL,
|
|
218
|
-
body TEXT NOT NULL,
|
|
219
|
-
PRIMARY KEY (submission_id, seq),
|
|
220
|
-
UNIQUE (submission_id, milestone_key)
|
|
221
|
-
)`;
|
|
222
|
-
sql`UPDATE pi_recovery_milestones
|
|
223
|
-
SET body = json_remove(
|
|
224
|
-
json_set(
|
|
225
|
-
body,
|
|
226
|
-
'$.approval.executionLevel', 'safe',
|
|
227
|
-
'$.approval.requiredExecutionLevel',
|
|
228
|
-
COALESCE(json_extract(body, '$.approval.risk'), 'safe')
|
|
229
|
-
),
|
|
230
|
-
'$.approval.risk'
|
|
231
|
-
)
|
|
232
|
-
WHERE json_valid(body)
|
|
233
|
-
AND json_extract(body, '$.version') = 1
|
|
234
|
-
AND json_extract(body, '$.type') = 'approval'
|
|
235
|
-
AND json_type(body, '$.turnId') = 'text'
|
|
236
|
-
AND json_type(body, '$.assemblyRevision') = 'text'
|
|
237
|
-
AND json_type(body, '$.approval') = 'object'
|
|
238
|
-
AND json_type(body, '$.approval.executionId') = 'text'
|
|
239
|
-
AND json_type(body, '$.approval.requestId') = 'text'
|
|
240
|
-
AND json_extract(body, '$.approval.source') IN (
|
|
241
|
-
'action', 'codemode', 'temporary-agent'
|
|
242
|
-
)
|
|
243
|
-
AND json_type(body, '$.approval.toolCallId') = 'text'
|
|
244
|
-
AND json_type(body, '$.approval.toolName') = 'text'
|
|
245
|
-
AND json_type(body, '$.approval.summary') = 'text'
|
|
246
|
-
AND json_type(body, '$.approval.inputJson') = 'text'
|
|
247
|
-
AND json_type(body, '$.approval.createdAt') IN ('integer', 'real')
|
|
248
|
-
AND json_extract(body, '$.approval.status') IN (
|
|
249
|
-
'pending', 'approved', 'rejected'
|
|
250
|
-
)
|
|
251
|
-
AND (
|
|
252
|
-
json_type(body, '$.approval.risk') IS NULL
|
|
253
|
-
OR json_type(body, '$.approval.risk') = 'null'
|
|
254
|
-
OR json_extract(body, '$.approval.risk') IN (
|
|
255
|
-
'low', 'medium', 'high'
|
|
256
|
-
)
|
|
257
|
-
)
|
|
258
|
-
AND json_type(body, '$.approval.executionLevel') IS NULL
|
|
259
|
-
AND json_type(body, '$.approval.requiredExecutionLevel') IS NULL`;
|
|
260
193
|
sql`CREATE TABLE IF NOT EXISTS pi_extension_context (
|
|
261
194
|
label TEXT PRIMARY KEY,
|
|
262
195
|
content TEXT NOT NULL,
|
|
@@ -7,29 +7,31 @@ import {
|
|
|
7
7
|
type FiberRecoveryContext,
|
|
8
8
|
type FiberRecoveryResult,
|
|
9
9
|
} from "agents";
|
|
10
|
-
import type {
|
|
10
|
+
import type { HarnessEvent } from "@earendil-works/pi-agent-core";
|
|
11
|
+
import type { UIMessageChunk } from "ai";
|
|
11
12
|
import {
|
|
12
13
|
AGENT_TYPES,
|
|
13
|
-
} from "../../../
|
|
14
|
-
import type { AgentType } from "../../../
|
|
14
|
+
} from "../../../tools/subagent-types/registry";
|
|
15
|
+
import type { AgentType } from "../../../tools/subagent-types/contract";
|
|
15
16
|
import type {
|
|
16
17
|
RuntimeProviderPort,
|
|
17
18
|
WorkspacePort,
|
|
18
|
-
} from "../../../
|
|
19
|
-
import {
|
|
19
|
+
} from "../../../config/ports";
|
|
20
|
+
import { HarnessStreamProjection } from "../../../conversation/harness-stream";
|
|
20
21
|
import {
|
|
21
22
|
createPiModels,
|
|
22
23
|
resolvePiModel,
|
|
23
|
-
|
|
24
|
-
} from "../../../
|
|
24
|
+
withProviderBoundary,
|
|
25
|
+
} from "../../../models";
|
|
25
26
|
import { runCloudflareSubAgent } from "./runner";
|
|
27
|
+
import { openCloudflareSession } from "../../../session";
|
|
26
28
|
import {
|
|
27
29
|
addSubagentUsage,
|
|
28
30
|
decodeSubagentCompletion,
|
|
29
31
|
emptySubagentUsage,
|
|
30
32
|
encodeSubagentCompletion,
|
|
31
|
-
} from "../../../
|
|
32
|
-
import type { RuntimeSubagentUsageMetrics } from "../../../
|
|
33
|
+
} from "../../../tools/subagent-runtime";
|
|
34
|
+
import type { RuntimeSubagentUsageMetrics } from "../../../tools/subagent-authority";
|
|
33
35
|
import { createCloudflareSubAgentTools } from "./tools";
|
|
34
36
|
|
|
35
37
|
type RunStatus =
|
|
@@ -92,24 +94,24 @@ function stringifyJson(value: unknown): string {
|
|
|
92
94
|
}
|
|
93
95
|
|
|
94
96
|
function progressFor(
|
|
95
|
-
event:
|
|
97
|
+
event: HarnessEvent,
|
|
96
98
|
): Omit<AgentToolProgressSnapshot, "at"> | null {
|
|
97
|
-
if (event.type === "
|
|
99
|
+
if (event.type === "run_start" || event.type === "run_resume") {
|
|
98
100
|
return { phase: "running", message: "SubAgent started" };
|
|
99
101
|
}
|
|
100
|
-
if (event.type === "
|
|
102
|
+
if (event.type === "tool_start") {
|
|
101
103
|
return {
|
|
102
104
|
phase: "tool",
|
|
103
105
|
message: `Running ${event.toolName}`,
|
|
104
106
|
};
|
|
105
107
|
}
|
|
106
|
-
if (event.type === "
|
|
108
|
+
if (event.type === "tool_update") {
|
|
107
109
|
return {
|
|
108
110
|
phase: "tool",
|
|
109
111
|
message: `${event.toolName} is still running`,
|
|
110
112
|
};
|
|
111
113
|
}
|
|
112
|
-
if (event.type === "
|
|
114
|
+
if (event.type === "tool_end") {
|
|
113
115
|
return {
|
|
114
116
|
phase: event.isError ? "tool-error" : "tool",
|
|
115
117
|
message: event.isError
|
|
@@ -362,6 +364,15 @@ export abstract class CloudflareSubAgent<
|
|
|
362
364
|
`;
|
|
363
365
|
|
|
364
366
|
const usage = this.readUsage(runId);
|
|
367
|
+
let streamSequence = 0;
|
|
368
|
+
let projection: HarnessStreamProjection | undefined;
|
|
369
|
+
const publish = (chunks: readonly UIMessageChunk[]) => {
|
|
370
|
+
for (const chunk of chunks) {
|
|
371
|
+
this.appendChunk(runId, stringifyJson({
|
|
372
|
+
v: 1, messageId: runId, sequence: streamSequence++, chunk,
|
|
373
|
+
}));
|
|
374
|
+
}
|
|
375
|
+
};
|
|
365
376
|
try {
|
|
366
377
|
const { provider, workspace, loader, outbound } =
|
|
367
378
|
await this.prepareExecution();
|
|
@@ -387,16 +398,19 @@ export abstract class CloudflareSubAgent<
|
|
|
387
398
|
);
|
|
388
399
|
},
|
|
389
400
|
});
|
|
390
|
-
|
|
391
|
-
const encoder = new PiChunkEncoder({
|
|
401
|
+
projection = new HarnessStreamProjection({
|
|
392
402
|
messageId: runId,
|
|
403
|
+
turnId: runId,
|
|
393
404
|
startedAt: this.readRun(runId)?.started_at ?? Date.now(),
|
|
394
405
|
});
|
|
395
406
|
const output = await runCloudflareSubAgent({
|
|
396
407
|
type,
|
|
397
408
|
input,
|
|
398
409
|
model,
|
|
399
|
-
|
|
410
|
+
models,
|
|
411
|
+
openSession: () => openCloudflareSession(this.ctx.storage),
|
|
412
|
+
operationId: runId,
|
|
413
|
+
streamFn: withProviderBoundary(models.streamSimple.bind(models)),
|
|
400
414
|
tools,
|
|
401
415
|
signal,
|
|
402
416
|
onEvent: (event) => {
|
|
@@ -404,20 +418,19 @@ export abstract class CloudflareSubAgent<
|
|
|
404
418
|
addSubagentUsage(usage, event.message.usage);
|
|
405
419
|
this.persistUsage(runId, usage);
|
|
406
420
|
}
|
|
407
|
-
|
|
408
|
-
this.appendChunk(runId, stringifyJson({
|
|
409
|
-
v: 1,
|
|
410
|
-
messageId: runId,
|
|
411
|
-
sequence: streamSequence++,
|
|
412
|
-
chunk,
|
|
413
|
-
}));
|
|
414
|
-
}
|
|
421
|
+
publish(projection!.event(event));
|
|
415
422
|
const progress = progressFor(event);
|
|
416
423
|
if (progress) this.persistProgress(runId, progress);
|
|
417
424
|
},
|
|
418
425
|
});
|
|
426
|
+
publish(projection.finish({ status: "completed", endedAt: Date.now() }));
|
|
419
427
|
this.completeRun(runId, output, usage);
|
|
420
428
|
} catch (error) {
|
|
429
|
+
if (projection) publish(projection.finish({
|
|
430
|
+
status: signal.aborted ? "aborted" : "failed",
|
|
431
|
+
endedAt: Date.now(),
|
|
432
|
+
error: { code: signal.aborted ? "aborted" : "failed", message: errorMessage(error) },
|
|
433
|
+
}));
|
|
421
434
|
this.failRun(
|
|
422
435
|
runId,
|
|
423
436
|
signal.aborted ? "aborted" : "error",
|
|
@@ -611,16 +624,33 @@ export abstract class CloudflareSubAgent<
|
|
|
611
624
|
typeof context.metadata?.runId === "string"
|
|
612
625
|
? context.metadata.runId
|
|
613
626
|
: context.idempotencyKey;
|
|
614
|
-
if (runId) {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
627
|
+
if (!runId) {
|
|
628
|
+
return { status: "interrupted", reason: "SubAgent run ID is missing" };
|
|
629
|
+
}
|
|
630
|
+
const row = this.readRun(runId);
|
|
631
|
+
if (!row) {
|
|
632
|
+
return { status: "interrupted", reason: "SubAgent run is missing" };
|
|
633
|
+
}
|
|
634
|
+
if (!TERMINAL.has(row.status)) {
|
|
635
|
+
const type = this.resolveType(row.agent_type);
|
|
636
|
+
const input = type.inputSchema.parse(parseJson(row.input_json));
|
|
637
|
+
await this.executeRun(runId, type, input, new AbortController().signal);
|
|
638
|
+
}
|
|
639
|
+
const recovered = this.readRun(runId);
|
|
640
|
+
if (recovered?.status === "completed") {
|
|
641
|
+
return { status: "completed", snapshot: { runId } };
|
|
642
|
+
}
|
|
643
|
+
if (recovered?.status === "aborted") {
|
|
644
|
+
return {
|
|
645
|
+
status: "aborted",
|
|
646
|
+
reason: recovered.error_message ?? "SubAgent run aborted",
|
|
647
|
+
snapshot: { runId },
|
|
648
|
+
};
|
|
620
649
|
}
|
|
621
650
|
return {
|
|
622
|
-
status: "
|
|
623
|
-
|
|
651
|
+
status: "error",
|
|
652
|
+
error: recovered?.error_message ?? "SubAgent recovery failed",
|
|
653
|
+
snapshot: { runId },
|
|
624
654
|
};
|
|
625
655
|
}
|
|
626
656
|
}
|