@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
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import { sha256Hex } from "../lib/artifacts";
|
|
1
2
|
import type {
|
|
2
3
|
RuntimeBindings,
|
|
3
4
|
RuntimeGatewaySession,
|
|
4
5
|
RuntimePlatformPort,
|
|
5
|
-
} from "
|
|
6
|
-
import type { RuntimeDegradation } from "
|
|
6
|
+
} from "./ports";
|
|
7
|
+
import type { RuntimeDegradation } from "./degradation";
|
|
7
8
|
import type {
|
|
8
9
|
RuntimeExtensionPermissions,
|
|
9
|
-
} from "
|
|
10
|
-
import type { RuntimeProfile } from "
|
|
11
|
-
import type { ExecutionLevel } from "
|
|
12
|
-
import type { RuntimeSnapshot } from "
|
|
13
|
-
import type { FinalizedPiToolSurface, PiRuntimeAssembly } from "../
|
|
10
|
+
} from "../context/extension/contracts";
|
|
11
|
+
import type { RuntimeProfile } from "./profile";
|
|
12
|
+
import type { ExecutionLevel } from "../lib/execution-level";
|
|
13
|
+
import type { RuntimeSnapshot } from "./assembler";
|
|
14
|
+
import type { FinalizedPiToolSurface, PiRuntimeAssembly } from "../context";
|
|
14
15
|
import {
|
|
15
16
|
assemblePiSystemContext,
|
|
16
17
|
assemblePiExtensions,
|
|
@@ -18,14 +19,35 @@ import {
|
|
|
18
19
|
type PiExtensionAssembly,
|
|
19
20
|
type PiExtensionContextContribution,
|
|
20
21
|
type PiLoadedExtension,
|
|
21
|
-
} from "../
|
|
22
|
+
} from "../context";
|
|
22
23
|
import {
|
|
23
24
|
createPiGatewayToolCandidates,
|
|
24
25
|
createPiMcpToolCandidates,
|
|
25
26
|
listExtensionsPiToolCandidate,
|
|
26
27
|
type PiMcpHost,
|
|
27
28
|
type PiToolCandidate,
|
|
28
|
-
} from "../
|
|
29
|
+
} from "../tools";
|
|
30
|
+
|
|
31
|
+
export interface RuntimeAssemblyPin {
|
|
32
|
+
readonly revision: string;
|
|
33
|
+
readonly descriptor: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** A saved pin is reusable only with its original Runtime key and intact descriptor. */
|
|
37
|
+
export async function validateRuntimeAssemblyPin(
|
|
38
|
+
runtimeKey: string,
|
|
39
|
+
pin: RuntimeAssemblyPin,
|
|
40
|
+
): Promise<boolean> {
|
|
41
|
+
if (!runtimeKey) {
|
|
42
|
+
throw new Error("Cannot safely recover a pinned Submission without its original Runtime key");
|
|
43
|
+
}
|
|
44
|
+
if (!pin.revision && !pin.descriptor) return false;
|
|
45
|
+
if (!pin.revision || !pin.descriptor) throw new Error("Submission assembly pin is incomplete");
|
|
46
|
+
if (pin.revision !== await sha256Hex(pin.descriptor)) {
|
|
47
|
+
throw new Error("Pinned Runtime assembly descriptor is invalid");
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
29
51
|
|
|
30
52
|
/**
|
|
31
53
|
* 本文件负责准备 Pi 的扩展与工具,并为每次提交固定可恢复的运行描述。
|
|
@@ -85,7 +107,7 @@ interface PreparedPiAssembly {
|
|
|
85
107
|
* 提供准备 Pi 所需的已校验 Runtime 快照和 Host 端口。
|
|
86
108
|
*
|
|
87
109
|
* @remarks
|
|
88
|
-
* `
|
|
110
|
+
* `HarnessRuntimeConfig.prepare` 在加载 Runtime 配置时传入它。
|
|
89
111
|
*
|
|
90
112
|
* 扩展绑定仍由 Host 创建,因为 Cloudflare 绑定属于 Worker 的能力边界。
|
|
91
113
|
*
|
|
@@ -128,13 +150,18 @@ export interface PreparedPiRuntime {
|
|
|
128
150
|
* 提供把一次提交固定到当前 Runtime 所需的值。
|
|
129
151
|
*
|
|
130
152
|
* @remarks
|
|
131
|
-
* Runtime 在写入提交前的准入阶段把它交给 `
|
|
153
|
+
* Runtime 在写入提交前的准入阶段把它交给 `HarnessRuntimeConfig.pin`。
|
|
132
154
|
*
|
|
133
155
|
* 扩展没有可读上下文时不需要读取函数,所以该端口保持可选。
|
|
134
156
|
*/
|
|
135
157
|
export interface PinPiRuntimeOptions {
|
|
136
158
|
readonly prepared: PreparedPiRuntime;
|
|
137
159
|
readonly baseRevision: string;
|
|
160
|
+
/**
|
|
161
|
+
* Whether this Submission may inherit automatic hot and cold Memory context.
|
|
162
|
+
* Scheduled task input is intentionally isolated from those sources.
|
|
163
|
+
*/
|
|
164
|
+
readonly includeMemory?: boolean;
|
|
138
165
|
/**
|
|
139
166
|
* 读取一个扩展要写入固定系统提示词的上下文。
|
|
140
167
|
*
|
|
@@ -165,7 +192,7 @@ export interface PinnedPiRuntime {
|
|
|
165
192
|
* 描述一条已存提交可以恢复到哪份 Pi 配置。
|
|
166
193
|
*
|
|
167
194
|
* @remarks
|
|
168
|
-
* `
|
|
195
|
+
* `HarnessRuntimeConfig.harnessInputs` 在打开或恢复 operation 前读取这个 JSON 结构。
|
|
169
196
|
*
|
|
170
197
|
* 基础版本作为准入时元数据保留,创建 Turn 时不与当前 Runtime 比较。
|
|
171
198
|
*/
|
|
@@ -227,9 +254,20 @@ function describeTools(candidates: readonly PiToolCandidate[]) {
|
|
|
227
254
|
description: candidate.tool.description ?? candidate.tool.label,
|
|
228
255
|
parameters: candidate.tool.parameters,
|
|
229
256
|
requiredExecutionLevel: candidate.requiredExecutionLevel,
|
|
257
|
+
...(candidate.confirmation ? { confirmation: true } : {}),
|
|
230
258
|
...(candidate.alwaysRequiresApproval
|
|
231
259
|
? { alwaysRequiresApproval: true }
|
|
232
260
|
: {}),
|
|
261
|
+
...(candidate.unattendedExecution
|
|
262
|
+
? {
|
|
263
|
+
unattendedExecution: {
|
|
264
|
+
capability: candidate.unattendedExecution.capability,
|
|
265
|
+
operation: candidate.unattendedExecution.operation,
|
|
266
|
+
objectConstrained:
|
|
267
|
+
candidate.unattendedExecution.objectForInput !== undefined,
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
: {}),
|
|
233
271
|
...(candidate.deferLoading ? { deferLoading: true } : {}),
|
|
234
272
|
...(candidate.source ? { source: candidate.source } : {}),
|
|
235
273
|
retry: piToolRetryPolicy(candidate),
|
|
@@ -282,7 +320,7 @@ function describeRuntime(
|
|
|
282
320
|
class PreparedRuntime implements PreparedPiRuntime {
|
|
283
321
|
// 把公开版本数据与受身份保护的内部准备状态放在同一个句柄里。
|
|
284
322
|
// 只有 preparePiRuntime 会构造它,并在返回前冻结实例。
|
|
285
|
-
// owner 使用对象身份区分
|
|
323
|
+
// owner 使用对象身份区分 HarnessRuntimeConfig,避免不同适配器的句柄被混用。
|
|
286
324
|
constructor(
|
|
287
325
|
readonly revisionDescriptor: string,
|
|
288
326
|
readonly degradations: readonly RuntimeDegradation[],
|
|
@@ -305,7 +343,7 @@ class PreparedRuntime implements PreparedPiRuntime {
|
|
|
305
343
|
}
|
|
306
344
|
|
|
307
345
|
/**
|
|
308
|
-
* 为创建它的
|
|
346
|
+
* 为创建它的 HarnessRuntimeConfig 打开准备句柄。
|
|
309
347
|
*
|
|
310
348
|
* @remarks
|
|
311
349
|
* 固定配置和创建 Turn 都会先调用它,再读取快照、装配结果或工具候选。
|
|
@@ -326,7 +364,7 @@ export function readPreparedPiRuntime(
|
|
|
326
364
|
* 读取已存的固定描述。
|
|
327
365
|
*
|
|
328
366
|
* @remarks
|
|
329
|
-
* `
|
|
367
|
+
* `HarnessRuntimeConfig.harnessInputs` 在新建或恢复 Pi operation 前调用它。
|
|
330
368
|
*
|
|
331
369
|
* Prepared Runtime 提供当前执行能力,descriptor 仅保留 Submission 固定的 Turn 字段。
|
|
332
370
|
*/
|
|
@@ -415,7 +453,7 @@ async function preparePiAssembly(
|
|
|
415
453
|
* 为一份已校验的 Runtime 快照准备扩展和工具状态。
|
|
416
454
|
*
|
|
417
455
|
* @remarks
|
|
418
|
-
* `
|
|
456
|
+
* `HarnessRuntimeConfig.prepare` 在 Runtime 配置阶段、快照生效前调用它。
|
|
419
457
|
*
|
|
420
458
|
* 冻结句柄会保存最终候选列表,对外只提供版本描述和降级结果。
|
|
421
459
|
*/
|
|
@@ -459,11 +497,14 @@ export async function pinPiRuntime(
|
|
|
459
497
|
): Promise<PinnedPiRuntime> {
|
|
460
498
|
const state = readPreparedPiRuntime(options.prepared, owner);
|
|
461
499
|
const { snapshot, assembly } = state;
|
|
500
|
+
const includeMemory = options.includeMemory !== false;
|
|
462
501
|
const context = await assemblePiSystemContext({
|
|
463
502
|
baseSystemPrompt: snapshot.pi.systemPrompt,
|
|
464
|
-
memory:
|
|
465
|
-
|
|
466
|
-
|
|
503
|
+
memory: includeMemory
|
|
504
|
+
? snapshot.profile.memory
|
|
505
|
+
: { ...snapshot.profile.memory, enabled: false },
|
|
506
|
+
memoryPort: includeMemory ? snapshot.bindings.memory : undefined,
|
|
507
|
+
workspace: includeMemory ? snapshot.bindings.workspace : undefined,
|
|
467
508
|
skills: snapshot.bindings.skills.sources,
|
|
468
509
|
extensionContexts: assembly.context,
|
|
469
510
|
readExtensionContext: options.readExtensionContext,
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
+
export type { RuntimeSchedulePreparation } from "../submission/contracts";
|
|
2
|
+
import type { RuntimeModelInputModality } from "./profile";
|
|
1
3
|
import type { SkillSource } from "agents/skills";
|
|
2
|
-
import type { ScheduleSpec } from "
|
|
3
|
-
import type { RuntimeActivityProjection } from "
|
|
4
|
+
import type { ScheduleSpec, RuntimeSchedulePreparation } from "../submission/contracts";
|
|
5
|
+
import type { RuntimeActivityProjection } from "../conversation/state";
|
|
4
6
|
import type { ExecutionLevel } from "../lib/execution-level";
|
|
5
7
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
6
|
-
import type { PiToolCandidate } from "../
|
|
8
|
+
import type { PiToolCandidate } from "../tools/runtime/contracts";
|
|
7
9
|
import type {
|
|
8
10
|
RuntimeEventConfirmation,
|
|
9
11
|
RuntimeLifecycleFact,
|
|
10
12
|
RuntimeSubagentUsageEvent,
|
|
11
13
|
RuntimeSubagentUsageMetrics,
|
|
12
|
-
} from "
|
|
14
|
+
} from "../tools/subagent/authority";
|
|
15
|
+
export type { RuntimeModelInputModality } from "./profile";
|
|
13
16
|
export type {
|
|
14
17
|
RuntimeEventConfirmation,
|
|
15
18
|
RuntimeLifecycleFact,
|
|
@@ -19,7 +22,7 @@ export type {
|
|
|
19
22
|
RuntimeSubmissionAdmissionHook,
|
|
20
23
|
RuntimeSubmissionAdmissionInput,
|
|
21
24
|
RuntimeSubmissionAdmissionResult,
|
|
22
|
-
} from "
|
|
25
|
+
} from "../tools/subagent/authority";
|
|
23
26
|
|
|
24
27
|
// #region Workspace 端口
|
|
25
28
|
|
|
@@ -624,7 +627,7 @@ export interface RuntimeGatewayPort {
|
|
|
624
627
|
}
|
|
625
628
|
|
|
626
629
|
/** Safe catalog from an external Host; credentials and SDK clients stay there. */
|
|
627
|
-
export type RuntimeMcpHost = import("../
|
|
630
|
+
export type RuntimeMcpHost = import("../tools/mcp").PiMcpHost & {
|
|
628
631
|
readonly servers: readonly import("./profile").RuntimeMcpServer[];
|
|
629
632
|
};
|
|
630
633
|
|
|
@@ -667,16 +670,25 @@ export interface RuntimeScheduleAgentSummary {
|
|
|
667
670
|
* 让 Runtime 通过 Host 管理当前用户的定时任务。
|
|
668
671
|
*
|
|
669
672
|
* @remarks
|
|
670
|
-
*
|
|
673
|
+
* Host 提供准备与提交操作;Runtime 在现有持久化审批中固定候选并等待用户确认。
|
|
671
674
|
*
|
|
672
|
-
*
|
|
675
|
+
* 任务事实、候选版本、授权检查和保存幂等由 Host 持有,不存放凭据。
|
|
673
676
|
*/
|
|
677
|
+
export interface RuntimeScheduleConfirmationPort {
|
|
678
|
+
/** Read-only preparation; bind the full candidate and authorization to this stable intent. */
|
|
679
|
+
prepare(request: RuntimeScheduleUpdate & { intentId: string; id?: string }): Promise<RuntimeSchedulePreparation>;
|
|
680
|
+
/** Atomically check candidate/version, live authorization and quotas. Replay must return the same task. */
|
|
681
|
+
commit(prepared: RuntimeSchedulePreparation, context: { intentId: string; signal: AbortSignal }): Promise<{ id: string }>;
|
|
682
|
+
}
|
|
683
|
+
|
|
674
684
|
export interface RuntimeSchedulePort {
|
|
685
|
+
/** Required for chat creation/editing. Legacy management callers retain their CRUD contract. */
|
|
686
|
+
confirmation?: RuntimeScheduleConfirmationPort;
|
|
675
687
|
/**
|
|
676
688
|
* 创建一条定时任务并返回它的 ID。
|
|
677
689
|
*
|
|
678
690
|
* @remarks
|
|
679
|
-
* `schedule`
|
|
691
|
+
* 保留给既有宿主管理调用者;聊天 `schedule` 只经 confirmation.commit 保存。
|
|
680
692
|
*
|
|
681
693
|
* Host 在该边界内绑定用户与会话,Runtime 不携带业务归属 ID。
|
|
682
694
|
*/
|
|
@@ -827,7 +839,7 @@ export interface RuntimeModelUsageEvent {
|
|
|
827
839
|
* 结算事件刻意不带参数,因为它只用来记账;开始事件必须带,因为它唯一的用处
|
|
828
840
|
* 就是让 Host 立刻知道「正在写的是什么」——只有工具名的话,「write 开始了」
|
|
829
841
|
* 和「一个网页正在生成」之间的差别就丢了,而后者才是盯着屏幕的人要看的。
|
|
830
|
-
* 参数本来就随 Tool
|
|
842
|
+
* 参数本来就随 Pi Tool 调用写入 Session,这里没有多暴露任何东西。
|
|
831
843
|
*/
|
|
832
844
|
export interface RuntimeToolStartEvent {
|
|
833
845
|
readonly submissionId: string;
|
|
@@ -942,12 +954,6 @@ export type RuntimeModelProtocol =
|
|
|
942
954
|
| "google-generative-ai"
|
|
943
955
|
| "openai-codex-responses";
|
|
944
956
|
|
|
945
|
-
export type RuntimeModelInputModality =
|
|
946
|
-
| "text"
|
|
947
|
-
| "image"
|
|
948
|
-
| "file"
|
|
949
|
-
| "audio"
|
|
950
|
-
| "video";
|
|
951
957
|
|
|
952
958
|
/**
|
|
953
959
|
* 描述一个已解析凭据的模型 API 端点。
|
|
@@ -1024,6 +1030,16 @@ export interface RuntimePlatformPort {
|
|
|
1024
1030
|
requiredExecutionLevel: ExecutionLevel;
|
|
1025
1031
|
signal: AbortSignal;
|
|
1026
1032
|
}): Promise<void>;
|
|
1033
|
+
/**
|
|
1034
|
+
* Match a pinned scheduled-task grant against the concrete Tool operation
|
|
1035
|
+
* and recheck the Host-owned live account authorization.
|
|
1036
|
+
*
|
|
1037
|
+
* This callback must fail closed by throwing a user-safe, specific reason.
|
|
1038
|
+
* It is called before dispatch and again at the effect boundary so a grant
|
|
1039
|
+
* revocation cannot be hidden by an earlier decision.
|
|
1040
|
+
*/
|
|
1041
|
+
/** @deprecated Scheduled execution is authorized locally by execution level. */
|
|
1042
|
+
authorizeUnattendedExecution?(request: unknown): Promise<void>;
|
|
1027
1043
|
}
|
|
1028
1044
|
|
|
1029
1045
|
/**
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
* @packageDocumentation
|
|
12
12
|
*/
|
|
13
13
|
export * from "./profile";
|
|
14
|
-
export * from "./
|
|
14
|
+
export * from "./assembly-view";
|
|
15
15
|
export * from "./runtime-config";
|
|
16
|
-
export * from "../
|
|
17
|
-
export * from "
|
|
18
|
-
export * from "
|
|
16
|
+
export * from "../conversation/message";
|
|
17
|
+
export * from "../submission/contracts";
|
|
18
|
+
export * from "../conversation/state";
|
|
19
19
|
export * from "../lib/execution-level";
|
|
20
|
-
export type { WorkspaceRevision, WorkspaceRevisionManifest } from "../workspace
|
|
20
|
+
export type { WorkspaceRevision, WorkspaceRevisionManifest } from "../tools/workspace/versioning";
|
|
21
21
|
export type {
|
|
22
22
|
RuntimeEventConfirmation,
|
|
23
23
|
RuntimeLifecycleFact,
|
|
@@ -27,4 +27,4 @@ export type {
|
|
|
27
27
|
RuntimeSubmissionAdmissionHook,
|
|
28
28
|
RuntimeSubmissionAdmissionInput,
|
|
29
29
|
RuntimeSubmissionAdmissionResult,
|
|
30
|
-
} from "
|
|
30
|
+
} from "../tools/subagent/authority";
|
|
@@ -1,212 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
DEFAULT_COMPACTION_SETTINGS,
|
|
7
|
-
estimateContextTokens,
|
|
8
|
-
estimateTokens,
|
|
9
|
-
prepareCompaction,
|
|
10
|
-
type AgentMessage,
|
|
11
|
-
type CompactionEntry,
|
|
12
|
-
type Entry,
|
|
13
|
-
} from "@earendil-works/pi-agent-core";
|
|
14
|
-
import type {
|
|
15
|
-
AssistantMessage,
|
|
16
|
-
Model,
|
|
17
|
-
Models,
|
|
18
|
-
RetryPolicy,
|
|
19
|
-
Usage,
|
|
20
|
-
} from "@earendil-works/pi-ai";
|
|
21
|
-
import { estimateStringTokens } from "agents/experimental/memory/utils";
|
|
22
|
-
import type { RuntimeMemoryPort } from "../../kernel/bindings";
|
|
23
|
-
import type { RuntimeDegradation } from "../../kernel/degradation";
|
|
24
|
-
import type { RuntimeMemoryProfile } from "../../kernel/profile";
|
|
25
|
-
import type { PiExtensionContextContribution } from "./extensions";
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* 压缩这一次 LLM 调用的重试策略。
|
|
29
|
-
*
|
|
30
|
-
* 为什么必须显式传:pi 的 `retryAssistantCall` 是 opt-in 的 —— d.ts 原话
|
|
31
|
-
* 「When `policy` is undefined or disabled, the first response is returned
|
|
32
|
-
* unchanged」。升到 0.83 不传这个参数,行为与 0.80.6 完全一样(零重试)。
|
|
33
|
-
*
|
|
34
|
-
* 为什么压缩值得重试:压缩失败不是「少一次摘要」,是**下一轮直接撞 provider
|
|
35
|
-
* 的上下文窗口上限、整个 turn 挂掉**。而它跑在 Workers 里,瞬时网络错误是常态。
|
|
36
|
-
*
|
|
37
|
-
* 为什么只有 2 次、退避从 500ms 起:压缩发生在 turn 的关键路径上,DO 的墙钟
|
|
38
|
-
* 是真金白银(等 LLM 不占 CPU 配额但占用户的等待)。2 次退避总计约 1.5s,
|
|
39
|
-
* 够穿过瞬时抖动,又不至于把一次失败拖成用户可感知的卡顿。
|
|
40
|
-
*/
|
|
41
|
-
const COMPACTION_RETRY: RetryPolicy = {
|
|
42
|
-
enabled: true,
|
|
43
|
-
maxRetries: 2,
|
|
44
|
-
baseDelayMs: 500,
|
|
45
|
-
};
|
|
1
|
+
import { estimateStringTokens } from "../lib/token-estimate";
|
|
2
|
+
import type { RuntimeMemoryPort } from "../config/ports";
|
|
3
|
+
import type { RuntimeDegradation } from "../config/degradation";
|
|
4
|
+
import type { RuntimeMemoryProfile } from "../config/profile";
|
|
5
|
+
import type { PiExtensionContextContribution } from "./extension/assembly";
|
|
46
6
|
|
|
47
7
|
const COLD_MEMORY_INDEX = "/userspace/memories/MEMORY.md";
|
|
48
8
|
const TRUNCATION_MARKER = "\n[truncated to memory budget]";
|
|
49
9
|
|
|
50
|
-
function compactionUsage(responses: readonly AssistantMessage[], requested: Model<any>) {
|
|
51
|
-
const [first, ...remaining] = responses;
|
|
52
|
-
return first ? { modelUsage: summarizeModelUsage(requested, [first, ...remaining]) } : {};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// #region Transcript compaction
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 把当前 Pi 会话分支压缩成下一轮可以直接使用的消息。
|
|
59
|
-
*
|
|
60
|
-
* @remarks
|
|
61
|
-
* Transcript 在每轮开始前传入当前分支、模型和 token 阈值,并在返回压缩条目后自行追加到 Session。
|
|
62
|
-
*
|
|
63
|
-
* 这里先用 Pi 的 Session 管线重建上下文,任何失败都退回未压缩消息,以避免压缩失败损坏持久化会话。
|
|
64
|
-
*
|
|
65
|
-
* 核心术语见包入口 `index.ts`。
|
|
66
|
-
*/
|
|
67
|
-
export async function compactPiContext(input: Readonly<{
|
|
68
|
-
branch: readonly Entry[];
|
|
69
|
-
compactAfterTokens: number;
|
|
70
|
-
force?: boolean;
|
|
71
|
-
models: Models;
|
|
72
|
-
model: Model<any>;
|
|
73
|
-
signal?: AbortSignal;
|
|
74
|
-
}>): Promise<{
|
|
75
|
-
messages: AgentMessage[];
|
|
76
|
-
compactionEntry?: Omit<
|
|
77
|
-
CompactionEntry,
|
|
78
|
-
"id" | "parentId" | "seq" | "timestamp"
|
|
79
|
-
>;
|
|
80
|
-
modelUsage?: {
|
|
81
|
-
api: string;
|
|
82
|
-
provider: string;
|
|
83
|
-
model: string;
|
|
84
|
-
responseModel?: string;
|
|
85
|
-
stopReason?: string;
|
|
86
|
-
usage: Usage;
|
|
87
|
-
};
|
|
88
|
-
didCompact: boolean;
|
|
89
|
-
degraded: boolean;
|
|
90
|
-
}> {
|
|
91
|
-
const responses: AssistantMessage[] = [];
|
|
92
|
-
const branch = [...input.branch];
|
|
93
|
-
const context = input.signal ? withAbortSignal(input.signal, BACKGROUND_CONTEXT) : BACKGROUND_CONTEXT;
|
|
94
|
-
let currentMessages = branch.flatMap((entry) =>
|
|
95
|
-
entry.type === "message" ? [entry.message] : []
|
|
96
|
-
);
|
|
97
|
-
try {
|
|
98
|
-
currentMessages = await buildSessionContext(branch, undefined, context);
|
|
99
|
-
const settings = DEFAULT_COMPACTION_SETTINGS;
|
|
100
|
-
if (
|
|
101
|
-
!settings.enabled ||
|
|
102
|
-
(!input.force && estimateContextTokens(currentMessages).tokens <
|
|
103
|
-
input.compactAfterTokens)
|
|
104
|
-
) {
|
|
105
|
-
return {
|
|
106
|
-
messages: currentMessages,
|
|
107
|
-
didCompact: false,
|
|
108
|
-
degraded: false,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const preparation = prepareCompaction(branch, settings);
|
|
113
|
-
if (!preparation.ok) {
|
|
114
|
-
return {
|
|
115
|
-
messages: currentMessages,
|
|
116
|
-
didCompact: false,
|
|
117
|
-
degraded: true,
|
|
118
|
-
...compactionUsage(responses, input.model),
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
if (!preparation.value) {
|
|
122
|
-
return {
|
|
123
|
-
messages: currentMessages,
|
|
124
|
-
didCompact: false,
|
|
125
|
-
degraded: false,
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const models = {
|
|
130
|
-
completeSimple: async (
|
|
131
|
-
model: Model<any>,
|
|
132
|
-
context: Parameters<Models["completeSimple"]>[1],
|
|
133
|
-
options?: Parameters<Models["completeSimple"]>[2],
|
|
134
|
-
) => {
|
|
135
|
-
const response = await input.models.completeSimple(model, context, options);
|
|
136
|
-
responses.push(response);
|
|
137
|
-
input.signal?.throwIfAborted();
|
|
138
|
-
return response;
|
|
139
|
-
},
|
|
140
|
-
} as Models;
|
|
141
|
-
const compacted = await compactPiTranscript(
|
|
142
|
-
preparation.value,
|
|
143
|
-
models,
|
|
144
|
-
input.model,
|
|
145
|
-
undefined,
|
|
146
|
-
undefined,
|
|
147
|
-
COMPACTION_RETRY,
|
|
148
|
-
undefined,
|
|
149
|
-
context,
|
|
150
|
-
);
|
|
151
|
-
if (!compacted.ok) {
|
|
152
|
-
return {
|
|
153
|
-
messages: currentMessages,
|
|
154
|
-
didCompact: false,
|
|
155
|
-
degraded: true,
|
|
156
|
-
...compactionUsage(responses, input.model),
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const compactionEntry = {
|
|
161
|
-
type: "compaction",
|
|
162
|
-
fromHook: false,
|
|
163
|
-
...compacted.value,
|
|
164
|
-
} satisfies Omit<
|
|
165
|
-
CompactionEntry,
|
|
166
|
-
"id" | "parentId" | "seq" | "timestamp"
|
|
167
|
-
>;
|
|
168
|
-
const previewEntry: CompactionEntry = {
|
|
169
|
-
...compactionEntry,
|
|
170
|
-
id: `compaction-preview:${branch[branch.length - 1]?.id ?? "root"}`,
|
|
171
|
-
parentId: branch[branch.length - 1]?.id ?? null,
|
|
172
|
-
timestamp: Date.now(),
|
|
173
|
-
seq: (branch.at(-1)?.seq ?? 0) + 1,
|
|
174
|
-
};
|
|
175
|
-
const messages = await buildSessionContext(
|
|
176
|
-
[...branch, previewEntry], undefined, context,
|
|
177
|
-
);
|
|
178
|
-
if (
|
|
179
|
-
input.force &&
|
|
180
|
-
messages.reduce((total, message) => total + estimateTokens(message), 0) >=
|
|
181
|
-
currentMessages.reduce(
|
|
182
|
-
(total, message) => total + estimateTokens(message),
|
|
183
|
-
0,
|
|
184
|
-
)
|
|
185
|
-
) {
|
|
186
|
-
return {
|
|
187
|
-
messages: currentMessages,
|
|
188
|
-
didCompact: false,
|
|
189
|
-
degraded: true,
|
|
190
|
-
...compactionUsage(responses, input.model),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
return {
|
|
194
|
-
messages,
|
|
195
|
-
compactionEntry,
|
|
196
|
-
...compactionUsage(responses, input.model),
|
|
197
|
-
didCompact: true,
|
|
198
|
-
degraded: false,
|
|
199
|
-
};
|
|
200
|
-
} catch {
|
|
201
|
-
return {
|
|
202
|
-
messages: currentMessages,
|
|
203
|
-
didCompact: false,
|
|
204
|
-
degraded: true,
|
|
205
|
-
...compactionUsage(responses, input.model),
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
10
|
// 作用:把一段上下文裁到指定 token 预算内。
|
|
211
11
|
// 调用:内存和 Extension 上下文在拼入 system prompt 前调用。
|
|
212
12
|
// 原因:二分搜索每次都用同一个 token 估算器验证,改成字符数截断会突破真实预算。
|
|
@@ -246,8 +46,6 @@ function renderBlock(
|
|
|
246
46
|
return `${separator}\n${label} (${description})\n${separator}\n${content}`;
|
|
247
47
|
}
|
|
248
48
|
|
|
249
|
-
// #endregion
|
|
250
|
-
|
|
251
49
|
// #region System context sources
|
|
252
50
|
|
|
253
51
|
// 作用:同时收集当前 Session 内存和用户管理的冷内存索引。
|
|
@@ -8,12 +8,12 @@ import type {
|
|
|
8
8
|
LoadedRuntimeExtension,
|
|
9
9
|
RuntimeExtensionConfig,
|
|
10
10
|
RuntimeExtensionPermissions,
|
|
11
|
-
} from "
|
|
12
|
-
import type { RuntimeDegradation } from "../../
|
|
13
|
-
import { withRuntimeLoadTimeout } from "../../
|
|
11
|
+
} from "./contracts";
|
|
12
|
+
import type { RuntimeDegradation } from "../../config/degradation";
|
|
13
|
+
import { withRuntimeLoadTimeout } from "../../config/runtime-load";
|
|
14
14
|
import { sanitizeExtensionName } from "../../lib/extension-name";
|
|
15
|
-
import type { PiToolCandidate } from "
|
|
16
|
-
import { createPiDeclaredToolCandidate } from "
|
|
15
|
+
import type { PiToolCandidate } from "../../tools/runtime/contracts";
|
|
16
|
+
import { createPiDeclaredToolCandidate } from "../../tools/adapters/declared";
|
|
17
17
|
|
|
18
18
|
export interface PiExtensionContextContribution {
|
|
19
19
|
readonly extensionName: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
artifactId,
|
|
2
3
|
type ArtifactRef,
|
|
3
4
|
serializeOutput,
|
|
4
5
|
sha256Hex,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
/**
|
|
30
31
|
* 持久化单个字符串叶子的上限。
|
|
31
32
|
*
|
|
32
|
-
* MUST ≥ 单页 read 的上限(见 `workspace
|
|
33
|
+
* MUST ≥ 单页 read 的上限(见 `tools/workspace/index.ts` 的 `READ_PAGE_MAX_CHARS`),
|
|
33
34
|
* 否则持久记录会比模型当轮看到的内容还少,会话恢复后出现凭空缺页。
|
|
34
35
|
*/
|
|
35
36
|
export const STORAGE_LEAF_MAX_CHARS = 64 * 1024;
|
|
@@ -44,8 +45,8 @@ export const SPILL_THRESHOLD = 32 * 1024;
|
|
|
44
45
|
/**
|
|
45
46
|
* 历史里一条旧 Tool 结果重放多少。
|
|
46
47
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
48
|
+
* 这条最紧,因为 `projectToolOutputForModel` 会把它应用到每个 Turn
|
|
49
|
+
* 重放的全部历史 Tool 结果:
|
|
49
50
|
* 放宽 1 KB 就是 N 条历史 × 1 KB。
|
|
50
51
|
*/
|
|
51
52
|
export const MODEL_REPLAY_THRESHOLD = 16 * 1024;
|
|
@@ -161,11 +162,26 @@ export async function spillDurableToolOutput(
|
|
|
161
162
|
text,
|
|
162
163
|
ext === "json" ? "application/json" : "text/plain",
|
|
163
164
|
);
|
|
165
|
+
if (!options.workspace.stat || !options.workspace.readFileBytes) {
|
|
166
|
+
throw new Error("Workspace artifact verification is unavailable");
|
|
167
|
+
}
|
|
168
|
+
const stat = await options.workspace.stat(path);
|
|
169
|
+
const expectedBytes = new TextEncoder().encode(text).byteLength;
|
|
170
|
+
if (!stat || stat.type !== "file" || stat.size !== expectedBytes) {
|
|
171
|
+
throw new Error("Workspace artifact failed size verification");
|
|
172
|
+
}
|
|
173
|
+
const stored = await options.workspace.readFileBytes(path);
|
|
174
|
+
if (!stored || new TextDecoder().decode(stored) !== text) {
|
|
175
|
+
throw new Error("Workspace artifact failed content verification");
|
|
176
|
+
}
|
|
164
177
|
return {
|
|
165
178
|
kind: "artifact_ref",
|
|
179
|
+
artifactId: artifactId(hash),
|
|
166
180
|
path,
|
|
167
|
-
bytes:
|
|
168
|
-
hash
|
|
181
|
+
bytes: expectedBytes,
|
|
182
|
+
hash,
|
|
183
|
+
workspaceRevision: stat.contentVersion ?? `${stat.updatedAt}:${stat.size}`,
|
|
184
|
+
availability: "available",
|
|
169
185
|
preview: text.slice(0, PREVIEW_CHARS),
|
|
170
186
|
// 出口指令必须是可执行的:只说“去 read 这个路径”会诱导模型整读,而整读一个
|
|
171
187
|
// 刚刚因为过大被外置的文件毫无意义。这里明确要求分页,并告知 read 会返回
|