@springbrand/agent-runtime 0.2.0-alpha.72 → 0.3.0-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 +7 -7
- package/src/{agent-tool-runtime.ts → adapter/cloudflare/agent-tool.ts} +1 -1
- package/src/adapter/cloudflare/agent.ts +1682 -0
- package/src/{db/index.ts → adapter/cloudflare/database.ts} +18 -55
- package/src/{runtime-agent.ts → adapter/cloudflare/define-agent.ts} +37 -42
- package/src/adapter/cloudflare/dynamic-worker-observability.ts +1 -1
- package/src/adapter/cloudflare/index.ts +18 -0
- package/src/adapter/cloudflare/resources/runtime-resources.ts +4 -4
- package/src/adapter/cloudflare/sandbox/adapter.ts +1 -1
- package/src/adapter/cloudflare/scheduling/schedule-rule.ts +322 -0
- package/src/adapter/cloudflare/scheduling/zoned-cron.ts +11 -6
- package/src/{db → adapter/cloudflare}/schema.ts +28 -80
- 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 -12
- 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} +45 -46
- 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 +190 -0
- package/src/config/index.ts +14 -0
- package/src/config/model-guidance.ts +21 -0
- package/src/{pi/runtime-adapter/assembly.ts → config/pinning.ts} +60 -19
- package/src/{kernel/bindings.ts → config/ports.ts} +32 -16
- 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} +5 -207
- 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 +21 -5
- package/src/conversation/harness-resume.ts +288 -0
- package/src/conversation/harness-stream.ts +99 -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 +113 -30
- package/src/{db/message-ui.repo.ts → conversation/repository.ts} +4 -0
- package/src/conversation/state.ts +196 -0
- package/src/harness/index.ts +7 -0
- package/src/harness/session-harness.ts +562 -0
- package/src/harness/submission-operation.ts +49 -0
- package/src/index.ts +38 -43
- package/src/lib/artifacts.ts +18 -0
- package/src/lib/execution-level.ts +13 -0
- package/src/lib/mcp.ts +1 -1
- package/src/lib/prompt.ts +7 -6
- package/src/lib/token-estimate.ts +8 -0
- package/src/{pi/runtime-adapter/models.ts → models/index.ts} +64 -17
- package/src/{pi/turn/tool-recovery.ts → session/cloudflare/legacy-tool-recovery.ts} +33 -525
- package/src/{pi/session → session/cloudflare}/migration.ts +404 -14
- package/src/{pi/session → session/cloudflare}/storage.ts +8 -36
- package/src/session/index.ts +39 -0
- package/src/skills/springbrand-worker-website/index.ts +1 -1
- package/src/submission/admission.ts +286 -0
- package/src/{kernel/receipts.ts → submission/contracts.ts} +56 -2
- 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} +117 -114
- package/src/submission/steer-delivery.ts +167 -0
- package/src/{db/steer.repo.ts → submission/steer-repository.ts} +27 -5
- package/src/submission/unattended.ts +40 -0
- 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/tools/README.md +44 -0
- package/src/{pi/tool/ai-adapter.ts → tools/adapters/ai-to-pi.ts} +6 -9
- package/src/{pi/tool → tools/adapters}/declared.ts +6 -2
- package/src/{pi/tool/nested-tools.ts → tools/adapters/pi-to-ai.ts} +2 -2
- package/src/tools/assistant/ask-user.ts +317 -0
- package/src/tools/assistant/candidate.ts +15 -0
- package/src/tools/assistant/followups.ts +34 -0
- package/src/tools/assistant/index.ts +19 -0
- package/src/tools/assistant/memory.ts +73 -0
- package/src/tools/assistant/plan.ts +98 -0
- package/src/{pi/tool → tools/assistant}/time.ts +1 -1
- package/src/{pi/tool/core-host.ts → tools/codemode/adapter.ts} +50 -49
- package/src/{pi/tool/core.ts → tools/codemode/index.ts} +35 -91
- package/src/tools/codemode/workspace-connector.ts +198 -0
- package/src/tools/extension/index.ts +42 -0
- package/src/tools/index.ts +32 -0
- package/src/{pi/tool → tools/mcp}/gateway.ts +19 -19
- package/src/{pi/tool/mcp.ts → tools/mcp/index.ts} +5 -5
- package/src/tools/runtime/approval/index.ts +1 -0
- package/src/{db/approval.repo.ts → tools/runtime/approval/repository.ts} +22 -41
- package/src/tools/runtime/compiler.ts +264 -0
- package/src/tools/runtime/contracts.ts +117 -0
- package/src/tools/runtime/decision-gate.ts +337 -0
- package/src/tools/runtime/human-decisions.ts +127 -0
- package/src/tools/runtime/interaction/index.ts +1 -0
- package/src/{db/interaction.repo.ts → tools/runtime/interaction/repository.ts} +1 -7
- package/src/tools/runtime/result.ts +22 -0
- package/src/tools/runtime/unattended-error.ts +4 -0
- package/src/tools/sandbox/index.ts +228 -0
- package/src/tools/schedule/index.ts +301 -0
- package/src/tools/skill/contracts.ts +20 -0
- package/src/tools/skill/index.ts +99 -0
- package/src/tools/skill/resources.ts +322 -0
- package/src/tools/skill/scripts.ts +168 -0
- package/src/{kernel/submission-authority.ts → tools/subagent/authority.ts} +31 -31
- package/src/{pi/tool/subagent.ts → tools/subagent/index.ts} +33 -36
- package/src/{db/agent-tool.repo.ts → tools/subagent/repository.ts} +1 -1
- package/src/{kernel/subagent-runtime.ts → tools/subagent/runtime.ts} +1 -1
- package/src/tools/subagent/temporary/approvals.ts +123 -0
- package/src/{layers/orchestration/temporary-agent/core.ts → tools/subagent/temporary/coordinator.ts} +41 -49
- package/src/tools/subagent/temporary/core.ts +53 -0
- package/src/{layers/orchestration/temporary-agent → tools/subagent/temporary}/runner.ts +1 -1
- package/src/{layers/orchestration/temporary-agent → tools/subagent/temporary}/workspace.ts +1 -4
- package/src/{pi/tool/web-fetch.ts → tools/web/fetch.ts} +4 -13
- package/src/tools/web/index.ts +2 -0
- package/src/tools/web/search/api.ts +1320 -0
- package/src/tools/web/search/index.ts +2 -0
- package/src/{pi/tool/web-search/web-search.ts → tools/web/search/search.ts} +5 -7
- package/src/{pi/tool/workspace-sandbox.ts → tools/workspace/index.ts} +12 -272
- package/src/{pi/tool/workspace-revision.ts → tools/workspace/revision.ts} +2 -2
- 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/base.ts +0 -550
- package/src/pi/tool/compiler.ts +0 -483
- package/src/pi/tool/index.ts +0 -38
- package/src/pi/tool/schedule.ts +0 -261
- package/src/pi/tool/skill.ts +0 -565
- package/src/pi/tool/web-search/api.ts +0 -1318
- package/src/pi/tool/web-search/index.ts +0 -2
- package/src/pi/tool/workspace-state-connector.ts +0 -146
- 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/{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 +1 -1
- /package/src/{workspace-versioning.ts → tools/workspace/versioning.ts} +0 -0
|
@@ -55,7 +55,8 @@ export function nextCronOccurrence(
|
|
|
55
55
|
for (const second of parsed.seconds) {
|
|
56
56
|
const wall = day + hour * 3_600_000 + minute * 60_000 + second * 1_000;
|
|
57
57
|
if (wall <= wallAfter) continue;
|
|
58
|
-
const resolved =
|
|
58
|
+
const resolved = wallTimeInstants(wall, timeZone)
|
|
59
|
+
.find((instant) => instant > after);
|
|
59
60
|
if (resolved !== undefined) return resolved;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
@@ -73,18 +74,22 @@ export function isValidTimeZone(timeZone: string): boolean {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
/**
|
|
78
|
+
* 所有本地墙上时间恰好等于 `wallUtc` 的 UTC 瞬时,升序。
|
|
79
|
+
*
|
|
80
|
+
* `wallUtc` 是"把本地钟点当作 UTC"的伪瞬时(见 {@link zoneOffsetMs})。
|
|
81
|
+
* 返回空数组 = 该钟点在当地被夏令时拨快抹掉;返回两个 = 拨慢导致同一钟点出现两次。
|
|
82
|
+
* 这是 `nextCronOccurrence` 与本地规则计算共用的唯一钟点解析边界。
|
|
83
|
+
*/
|
|
84
|
+
export function wallTimeInstants(wallUtc: number, timeZone: string): number[] {
|
|
77
85
|
const offsets = new Set([
|
|
78
|
-
zoneOffsetMs(after, timeZone),
|
|
79
86
|
zoneOffsetMs(wallUtc - 2 * 86_400_000, timeZone),
|
|
80
87
|
zoneOffsetMs(wallUtc, timeZone),
|
|
81
88
|
zoneOffsetMs(wallUtc + 2 * 86_400_000, timeZone),
|
|
82
89
|
]);
|
|
83
90
|
return [...offsets]
|
|
84
91
|
.map((offset) => wallUtc - offset)
|
|
85
|
-
.filter((instant) =>
|
|
86
|
-
instant > after && instant + zoneOffsetMs(instant, timeZone) === wallUtc
|
|
87
|
-
)
|
|
92
|
+
.filter((instant) => instant + zoneOffsetMs(instant, timeZone) === wallUtc)
|
|
88
93
|
.sort((left, right) => left - right);
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -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,16 +51,17 @@ 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("
|
|
66
|
-
sql`ALTER TABLE pi_submissions
|
|
67
|
-
|
|
54
|
+
if (!submissionColumns.has("origin")) {
|
|
55
|
+
sql`ALTER TABLE pi_submissions ADD COLUMN origin TEXT NOT NULL DEFAULT 'user'`;
|
|
56
|
+
}
|
|
57
|
+
if (!submissionColumns.has("scheduled_max_execution_level")) {
|
|
58
|
+
sql`ALTER TABLE pi_submissions ADD COLUMN scheduled_max_execution_level TEXT`;
|
|
68
59
|
}
|
|
69
|
-
if (!submissionColumns.has("
|
|
70
|
-
sql`ALTER TABLE pi_submissions ADD COLUMN
|
|
60
|
+
if (!submissionColumns.has("unattended_execution_grant_json")) {
|
|
61
|
+
sql`ALTER TABLE pi_submissions ADD COLUMN unattended_execution_grant_json TEXT`;
|
|
71
62
|
}
|
|
72
|
-
if (!submissionColumns.has("
|
|
73
|
-
sql`ALTER TABLE pi_submissions
|
|
74
|
-
ADD COLUMN context_overflow_retried INTEGER NOT NULL DEFAULT 0`;
|
|
63
|
+
if (!submissionColumns.has("unattended_failure")) {
|
|
64
|
+
sql`ALTER TABLE pi_submissions ADD COLUMN unattended_failure TEXT`;
|
|
75
65
|
}
|
|
76
66
|
sql`CREATE UNIQUE INDEX IF NOT EXISTS pi_submissions_one_running
|
|
77
67
|
ON pi_submissions(status)
|
|
@@ -80,20 +70,21 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
80
70
|
steer_id TEXT PRIMARY KEY,
|
|
81
71
|
submission_id TEXT NOT NULL,
|
|
82
72
|
message_id TEXT NOT NULL UNIQUE,
|
|
73
|
+
harness_entry_id TEXT,
|
|
83
74
|
canonical_json TEXT NOT NULL,
|
|
84
75
|
ui_message_json TEXT,
|
|
85
76
|
created_at INTEGER NOT NULL
|
|
86
77
|
)`;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
const steerColumns = new Set(
|
|
79
|
+
sql<{ name: string }>`PRAGMA table_info(pi_pending_steers)`
|
|
80
|
+
.map((column) => column.name),
|
|
81
|
+
);
|
|
82
|
+
if (!steerColumns.has("harness_entry_id")) {
|
|
83
|
+
sql`ALTER TABLE pi_pending_steers ADD COLUMN harness_entry_id TEXT`;
|
|
84
|
+
}
|
|
85
|
+
sql`CREATE UNIQUE INDEX IF NOT EXISTS pi_pending_steers_harness_entry_id
|
|
86
|
+
ON pi_pending_steers(harness_entry_id)
|
|
87
|
+
WHERE harness_entry_id IS NOT NULL`;
|
|
97
88
|
sql`CREATE TABLE IF NOT EXISTS pi_turn_event_outbox (
|
|
98
89
|
event_id TEXT PRIMARY KEY,
|
|
99
90
|
body TEXT NOT NULL,
|
|
@@ -177,6 +168,9 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
177
168
|
.map((column) => column.name),
|
|
178
169
|
);
|
|
179
170
|
let columns = approvalColumns();
|
|
171
|
+
if (!columns.has("confirmation_json")) {
|
|
172
|
+
sql`ALTER TABLE pi_approvals ADD COLUMN confirmation_json TEXT`;
|
|
173
|
+
}
|
|
180
174
|
if (!columns.has("execution_level")) {
|
|
181
175
|
// 旧 Session 没有持久化当时的授权档位,safe 失败关闭;只影响旧 pending 回执展示,不会静默放行。
|
|
182
176
|
sql`ALTER TABLE pi_approvals
|
|
@@ -211,52 +205,6 @@ export function initializeSchema(sql: SqlTaggedTemplate): void {
|
|
|
211
205
|
responded_at INTEGER,
|
|
212
206
|
UNIQUE (submission_id, tool_call_id)
|
|
213
207
|
)`;
|
|
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
208
|
sql`CREATE TABLE IF NOT EXISTS pi_extension_context (
|
|
261
209
|
label TEXT PRIMARY KEY,
|
|
262
210
|
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
|
}
|