@springbrand/agent-runtime 0.3.0-alpha.2 → 0.3.0-alpha.21

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.
Files changed (131) hide show
  1. package/package.json +11 -9
  2. package/src/adapter/cloudflare/agent.ts +233 -179
  3. package/src/adapter/cloudflare/define-agent.ts +252 -104
  4. package/src/adapter/cloudflare/index.ts +18 -0
  5. package/src/adapter/cloudflare/scheduling/schedule-rule.ts +322 -0
  6. package/src/adapter/cloudflare/scheduling/zoned-cron.ts +11 -6
  7. package/src/adapter/cloudflare/schema.ts +21 -2
  8. package/src/adapter/cloudflare/subagent/definition.ts +25 -13
  9. package/src/adapter/cloudflare/subagent/runner.ts +43 -50
  10. package/src/adapter/cloudflare/subagent/tools.ts +4 -4
  11. package/src/adapter/cloudflare/universal-agent/preparation.ts +3 -3
  12. package/src/adapter/cloudflare/universal-agent/tools.ts +4 -6
  13. package/src/adapter/cloudflare/workspace/version-control.ts +1 -1
  14. package/src/config/activation.ts +13 -15
  15. package/src/config/agent-context.ts +1 -1
  16. package/src/config/assembler.ts +48 -31
  17. package/src/config/assembly-snapshot.ts +1 -1
  18. package/src/config/definition.ts +1 -1
  19. package/src/config/harness-runtime.ts +77 -49
  20. package/src/config/index.ts +1 -1
  21. package/src/config/model-guidance.ts +20 -0
  22. package/src/config/ports.ts +57 -7
  23. package/src/config/{pinning.ts → prepared-runtime.ts} +59 -123
  24. package/src/config/public-contracts.ts +2 -2
  25. package/src/config/runtime-config.ts +2 -1
  26. package/src/context/assembly.ts +1 -1
  27. package/src/context/extension/assembly.ts +2 -2
  28. package/src/context/memory/budget/gate.ts +19 -3
  29. package/src/conversation/harness-resume.ts +89 -238
  30. package/src/conversation/harness-stream.ts +87 -71
  31. package/src/conversation/history.ts +154 -152
  32. package/src/conversation/message/contract.ts +28 -4
  33. package/src/conversation/message/conversion.ts +46 -5
  34. package/src/conversation/message/projection.ts +61 -21
  35. package/src/conversation/session-entry.ts +29 -0
  36. package/src/conversation/state.ts +23 -2
  37. package/src/harness/governance.ts +206 -0
  38. package/src/harness/index.ts +3 -0
  39. package/src/harness/session-harness.ts +269 -445
  40. package/src/harness/submission-operation.ts +15 -40
  41. package/src/index.ts +18 -8
  42. package/src/lib/artifacts.ts +18 -0
  43. package/src/lib/execution-level.ts +13 -0
  44. package/src/lib/prompt.ts +9 -10
  45. package/src/lib/token-estimate.ts +8 -0
  46. package/src/model-protocol/openrouter.ts +41 -0
  47. package/src/models/index.ts +200 -35
  48. package/src/models/openrouter/messages.ts +13 -8
  49. package/src/models/openrouter/openai.ts +200 -0
  50. package/src/models/openrouter/protocol-response.ts +85 -0
  51. package/src/models/provider-streams.ts +45 -0
  52. package/src/session/cloudflare/migration.ts +382 -864
  53. package/src/session/cloudflare/storage.ts +13 -536
  54. package/src/session/index.ts +22 -35
  55. package/src/skills/springbrand-worker-website/index.ts +1 -1
  56. package/src/submission/admission.ts +20 -30
  57. package/src/submission/contracts.ts +42 -2
  58. package/src/submission/delivery.ts +1 -1
  59. package/src/submission/finalization.ts +36 -15
  60. package/src/submission/lifecycle.ts +28 -15
  61. package/src/submission/repository.ts +97 -49
  62. package/src/submission/steer-delivery.ts +32 -76
  63. package/src/submission/unattended.ts +40 -0
  64. package/src/telemetry/contract.ts +0 -1
  65. package/src/telemetry/coordinator.ts +1 -1
  66. package/src/telemetry/runtime-telemetry.ts +0 -4
  67. package/src/telemetry/subagent-lifecycle.ts +1 -1
  68. package/src/telemetry/turn-events.ts +35 -25
  69. package/src/tools/README.md +44 -0
  70. package/src/tools/{ai-adapter.ts → adapters/ai-to-pi.ts} +6 -9
  71. package/src/tools/{declared.ts → adapters/declared.ts} +6 -2
  72. package/src/tools/{nested-tools.ts → adapters/pi-to-ai.ts} +4 -4
  73. package/src/tools/assistant/ask-user.ts +319 -0
  74. package/src/tools/assistant/candidate.ts +15 -0
  75. package/src/tools/assistant/followups.ts +34 -0
  76. package/src/tools/assistant/index.ts +19 -0
  77. package/src/tools/assistant/memory.ts +73 -0
  78. package/src/tools/assistant/plan.ts +98 -0
  79. package/src/tools/{time.ts → assistant/time.ts} +1 -1
  80. package/src/tools/{core-host.ts → codemode/adapter.ts} +50 -53
  81. package/src/tools/{core.ts → codemode/index.ts} +36 -92
  82. package/src/tools/codemode/workspace-connector.ts +198 -0
  83. package/src/tools/extension/index.ts +42 -0
  84. package/src/tools/index.ts +29 -26
  85. package/src/tools/{gateway.ts → mcp/gateway.ts} +19 -19
  86. package/src/tools/{mcp.ts → mcp/index.ts} +5 -5
  87. package/src/tools/runtime/activation.ts +40 -0
  88. package/src/tools/{approval → runtime/approval}/repository.ts +13 -12
  89. package/src/tools/runtime/compiler.ts +246 -0
  90. package/src/tools/runtime/contracts.ts +140 -0
  91. package/src/tools/{decision-gate.ts → runtime/decision-gate.ts} +149 -39
  92. package/src/tools/{human-decisions.ts → runtime/human-decisions.ts} +4 -4
  93. package/src/tools/{interaction → runtime/interaction}/repository.ts +1 -7
  94. package/src/tools/runtime/result.ts +22 -0
  95. package/src/tools/runtime/unattended-error.ts +4 -0
  96. package/src/tools/sandbox/index.ts +228 -0
  97. package/src/tools/schedule/index.ts +301 -0
  98. package/src/tools/skill/contracts.ts +20 -0
  99. package/src/tools/skill/index.ts +99 -0
  100. package/src/tools/skill/resources.ts +322 -0
  101. package/src/tools/skill/scripts.ts +168 -0
  102. package/src/tools/{subagent-authority.ts → subagent/authority.ts} +31 -31
  103. package/src/tools/{subagent.ts → subagent/index.ts} +34 -37
  104. package/src/tools/{subagent-run-repository.ts → subagent/repository.ts} +1 -1
  105. package/src/tools/{subagent-runtime.ts → subagent/runtime.ts} +1 -1
  106. package/src/tools/{temporary-agent → subagent/temporary}/approvals.ts +4 -7
  107. package/src/tools/{temporary-agent → subagent/temporary}/core.ts +2 -3
  108. package/src/tools/{temporary-agent → subagent/temporary}/runner.ts +1 -1
  109. package/src/tools/{temporary-agent → subagent/temporary}/workspace.ts +1 -4
  110. package/src/tools/{web-fetch.ts → web/fetch.ts} +4 -13
  111. package/src/tools/web/index.ts +2 -0
  112. package/src/tools/web/search/api.ts +1322 -0
  113. package/src/tools/web/search/index.ts +2 -0
  114. package/src/tools/{web-search/web-search.ts → web/search/search.ts} +5 -7
  115. package/src/tools/{workspace-sandbox.ts → workspace/index.ts} +12 -272
  116. package/src/tools/{workspace-revision.ts → workspace/revision.ts} +3 -3
  117. package/src/tools/base.ts +0 -534
  118. package/src/tools/compiler.ts +0 -327
  119. package/src/tools/schedule.ts +0 -261
  120. package/src/tools/skill.ts +0 -565
  121. package/src/tools/web-search/api.ts +0 -1318
  122. package/src/tools/web-search/index.ts +0 -2
  123. package/src/tools/workspace-state-connector.ts +0 -146
  124. package/src/tools/{approval → runtime/approval}/index.ts +0 -0
  125. package/src/tools/{interaction → runtime/interaction}/index.ts +0 -0
  126. package/src/tools/{temporary-agent → subagent/temporary}/coordinator.ts +0 -0
  127. package/src/tools/{subagent-types → subagent/types}/contract.ts +0 -0
  128. package/src/tools/{subagent-types → subagent/types}/extract/index.ts +0 -0
  129. package/src/tools/{subagent-types → subagent/types}/fanout/index.ts +0 -0
  130. package/src/tools/{subagent-types → subagent/types}/registry.ts +1 -1
  131. /package/src/tools/{workspace-versioning.ts → workspace/versioning.ts} +0 -0
@@ -1,16 +1,17 @@
1
+ export type { RuntimeSchedulePreparation } from "../submission/contracts";
1
2
  import type { RuntimeModelInputModality } from "./profile";
2
3
  import type { SkillSource } from "agents/skills";
3
- import type { ScheduleSpec } from "../submission/contracts";
4
+ import type { ScheduleSpec, RuntimeSchedulePreparation } from "../submission/contracts";
4
5
  import type { RuntimeActivityProjection } from "../conversation/state";
5
6
  import type { ExecutionLevel } from "../lib/execution-level";
6
7
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
7
- import type { PiToolCandidate } from "../tools/compiler";
8
+ import type { PiToolCandidate } from "../tools/runtime/contracts";
8
9
  import type {
9
10
  RuntimeEventConfirmation,
10
11
  RuntimeLifecycleFact,
11
12
  RuntimeSubagentUsageEvent,
12
13
  RuntimeSubagentUsageMetrics,
13
- } from "../tools/subagent-authority";
14
+ } from "../tools/subagent/authority";
14
15
  export type { RuntimeModelInputModality } from "./profile";
15
16
  export type {
16
17
  RuntimeEventConfirmation,
@@ -21,7 +22,7 @@ export type {
21
22
  RuntimeSubmissionAdmissionHook,
22
23
  RuntimeSubmissionAdmissionInput,
23
24
  RuntimeSubmissionAdmissionResult,
24
- } from "../tools/subagent-authority";
25
+ } from "../tools/subagent/authority";
25
26
 
26
27
  // #region Workspace 端口
27
28
 
@@ -669,16 +670,25 @@ export interface RuntimeScheduleAgentSummary {
669
670
  * 让 Runtime 通过 Host 管理当前用户的定时任务。
670
671
  *
671
672
  * @remarks
672
- * Schedule Plugin 在装配时把它交给基础工具,模型在用户要求创建、查询或取消时调用。
673
+ * Host 提供准备与提交操作;Runtime 在现有持久化审批中固定候选并等待用户确认。
673
674
  *
674
- * 任务归属和持久化留在 Host,Runtime 只传递 `ScheduleSpec` 和窄结果。
675
+ * 任务事实、候选版本、授权检查和保存幂等由 Host 持有,不存放凭据。
675
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
+
676
684
  export interface RuntimeSchedulePort {
685
+ /** Required for chat creation/editing. Legacy management callers retain their CRUD contract. */
686
+ confirmation?: RuntimeScheduleConfirmationPort;
677
687
  /**
678
688
  * 创建一条定时任务并返回它的 ID。
679
689
  *
680
690
  * @remarks
681
- * `schedule` 工具在把用户的时间与提示词组成 `ScheduleSpec` 后调用。
691
+ * 保留给既有宿主管理调用者;聊天 `schedule` 只经 confirmation.commit 保存。
682
692
  *
683
693
  * Host 在该边界内绑定用户与会话,Runtime 不携带业务归属 ID。
684
694
  */
@@ -940,6 +950,8 @@ export interface RuntimeBrowserPort {
940
950
  export type RuntimeModelProtocol =
941
951
  | "openai-chat"
942
952
  | "openrouter-messages"
953
+ | "openrouter-chat"
954
+ | "openrouter-responses"
943
955
  | "anthropic-messages"
944
956
  | "google-generative-ai"
945
957
  | "openai-codex-responses";
@@ -953,6 +965,31 @@ export type RuntimeModelProtocol =
953
965
  *
954
966
  * 凭据只留在 Port 对象,不进入 `RuntimeProfile` 或持久状态;术语见 `../index.ts`。
955
967
  */
968
+ export type RuntimeModelThinkingLevel =
969
+ | "off"
970
+ | "minimal"
971
+ | "low"
972
+ | "medium"
973
+ | "high"
974
+ | "xhigh"
975
+ | "max";
976
+
977
+ export interface RuntimeModelMetadata {
978
+ readonly name: string;
979
+ readonly reasoning: boolean;
980
+ readonly contextWindow: number;
981
+ readonly maxTokens: number;
982
+ readonly cost: Readonly<{
983
+ input: number;
984
+ output: number;
985
+ cacheRead: number;
986
+ cacheWrite: number;
987
+ }>;
988
+ readonly thinkingLevelMap?: Readonly<
989
+ Partial<Record<RuntimeModelThinkingLevel, string | null>>
990
+ >;
991
+ }
992
+
956
993
  export interface RuntimeModelEndpoint {
957
994
  protocol: RuntimeModelProtocol;
958
995
  /** Resolved credential; never enters RuntimeProfile or persisted state. */
@@ -967,6 +1004,9 @@ export interface RuntimeModelEndpoint {
967
1004
  >;
968
1005
  /** OpenRouter upstream provider pins keyed by model ID; pinned requests never fall back. */
969
1006
  openRouterProviderPins?: Readonly<Record<string, string>>;
1007
+ /** OpenRouter provider ordering; omitted keeps OpenRouter's default routing. */
1008
+ openRouterProviderSort?: "price" | "throughput" | "latency";
1009
+ modelMetadata?: Readonly<Record<string, RuntimeModelMetadata>>;
970
1010
  }
971
1011
 
972
1012
  /**
@@ -1020,6 +1060,16 @@ export interface RuntimePlatformPort {
1020
1060
  requiredExecutionLevel: ExecutionLevel;
1021
1061
  signal: AbortSignal;
1022
1062
  }): Promise<void>;
1063
+ /**
1064
+ * Match a pinned scheduled-task grant against the concrete Tool operation
1065
+ * and recheck the Host-owned live account authorization.
1066
+ *
1067
+ * This callback must fail closed by throwing a user-safe, specific reason.
1068
+ * It is called before dispatch and again at the effect boundary so a grant
1069
+ * revocation cannot be hidden by an earlier decision.
1070
+ */
1071
+ /** @deprecated Scheduled execution is authorized locally by execution level. */
1072
+ authorizeUnattendedExecution?(request: unknown): Promise<void>;
1023
1073
  }
1024
1074
 
1025
1075
  /**
@@ -1,4 +1,3 @@
1
- import { sha256Hex } from "../lib/artifacts";
2
1
  import type {
3
2
  RuntimeBindings,
4
3
  RuntimeGatewaySession,
@@ -9,7 +8,6 @@ import type {
9
8
  RuntimeExtensionPermissions,
10
9
  } from "../context/extension/contracts";
11
10
  import type { RuntimeProfile } from "./profile";
12
- import type { ExecutionLevel } from "../lib/execution-level";
13
11
  import type { RuntimeSnapshot } from "./assembler";
14
12
  import type { FinalizedPiToolSurface, PiRuntimeAssembly } from "../context";
15
13
  import {
@@ -28,29 +26,8 @@ import {
28
26
  type PiToolCandidate,
29
27
  } from "../tools";
30
28
 
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
- }
51
-
52
29
  /**
53
- * 本文件负责准备 Pi 的扩展与工具,并为每次提交固定可恢复的运行描述。
30
+ * 本文件负责准备当前 Pi 的扩展、工具与系统上下文。
54
31
  *
55
32
  * @remarks
56
33
  * 核心术语见本目录入口 `./index.ts`,这里不重复定义。
@@ -93,8 +70,8 @@ interface PreparePiAssemblyOptions {
93
70
  ) => Fetcher;
94
71
  }
95
72
 
96
- // 暴露后续准备和固定阶段会读取的扩展装配结果。
97
- // preparePiRuntime 读取工具与降级,pinPiRuntime 读取上下文贡献。
73
+ // 暴露后续准备和执行阶段会读取的扩展装配结果。
74
+ // preparePiRuntime 读取工具与降级,assembleCurrentPiContext 读取上下文贡献。
98
75
  // 访问器直接代理扩展装配,避免维护会漂移的副本。
99
76
  interface PreparedPiAssembly {
100
77
  readonly loaded: readonly PiLoadedExtension[];
@@ -133,10 +110,10 @@ export interface PreparePiRuntimeOptions {
133
110
  }
134
111
 
135
112
  /**
136
- * 表示已经准备好、但尚未固定到某次提交的 Pi 配置。
113
+ * 表示已准备好供当前执行使用的 Pi 配置。
137
114
  *
138
115
  * @remarks
139
- * Runtime 在配置完成后保存这个句柄,并在提交准入或创建 Turn 时传回。
116
+ * Runtime 在配置完成后保存这个句柄,并在创建 Turn 时传回。
140
117
  *
141
118
  * 公开形状只给出版本描述和加载降级,调用方不会直接拿到可变的装配状态。
142
119
  */
@@ -147,21 +124,25 @@ export interface PreparedPiRuntime {
147
124
  }
148
125
 
149
126
  /**
150
- * 提供把一次提交固定到当前 Runtime 所需的值。
127
+ * 当前执行切片读取系统上下文所需的值。
151
128
  *
152
129
  * @remarks
153
- * Runtime 在写入提交前的准入阶段把它交给 `HarnessRuntimeConfig.pin`。
130
+ * Runtime 在打开或恢复 Harness 前把它交给 `HarnessRuntimeConfig.harnessInputs`。
154
131
  *
155
132
  * 扩展没有可读上下文时不需要读取函数,所以该端口保持可选。
156
133
  */
157
- export interface PinPiRuntimeOptions {
134
+ export interface CurrentPiContextOptions {
158
135
  readonly prepared: PreparedPiRuntime;
159
- readonly baseRevision: string;
160
136
  /**
161
- * 读取一个扩展要写入固定系统提示词的上下文。
137
+ * Whether this Submission may inherit automatic hot and cold Memory context.
138
+ * Scheduled task input is intentionally isolated from those sources.
139
+ */
140
+ readonly includeMemory?: boolean;
141
+ /**
142
+ * 读取一个扩展对当前系统提示词的上下文贡献。
162
143
  *
163
144
  * @remarks
164
- * pinPiRuntime 在准入阶段为已加载扩展声明的上下文贡献调用它。
145
+ * 每次装配 Harness 输入时为已加载扩展读取当前上下文。
165
146
  *
166
147
  * 本模块不持有扩展上下文存储,所以读取端口必须留在 Host。
167
148
  */
@@ -170,40 +151,6 @@ export interface PinPiRuntimeOptions {
170
151
  ) => Promise<string | null>;
171
152
  }
172
153
 
173
- /**
174
- * 返回已经固定到一次提交的描述和上下文降级。
175
- *
176
- * @remarks
177
- * Runtime 在准入时持久化描述,并在创建 Turn 时传回。
178
- *
179
- * 固定这些值可让恢复继续使用当时已经准入的配置。
180
- */
181
- export interface PinnedPiRuntime {
182
- readonly descriptor: string;
183
- readonly degradations: readonly RuntimeDegradation[];
184
- }
185
-
186
- /**
187
- * 描述一条已存提交可以恢复到哪份 Pi 配置。
188
- *
189
- * @remarks
190
- * `HarnessRuntimeConfig.harnessInputs` 在打开或恢复 operation 前读取这个 JSON 结构。
191
- *
192
- * 基础版本作为准入时元数据保留,创建 Turn 时不与当前 Runtime 比较。
193
- */
194
- export interface PinnedPiRuntimeDescriptor {
195
- readonly version: 1;
196
- readonly baseRevision: string;
197
- readonly model: string;
198
- readonly provider: string;
199
- readonly thinking: RuntimeSnapshot["pi"]["thinkingLevel"];
200
- readonly systemPrompt: string;
201
- readonly executionLevel: ExecutionLevel;
202
- readonly deny: readonly string[];
203
- readonly tools: readonly ReturnType<typeof describeTools>[number][];
204
- readonly [key: string]: unknown;
205
- }
206
-
207
154
  /**
208
155
  * 保存创建 Pi Turn 所需的内部准备结果。
209
156
  *
@@ -249,9 +196,20 @@ function describeTools(candidates: readonly PiToolCandidate[]) {
249
196
  description: candidate.tool.description ?? candidate.tool.label,
250
197
  parameters: candidate.tool.parameters,
251
198
  requiredExecutionLevel: candidate.requiredExecutionLevel,
199
+ ...(candidate.confirmation ? { confirmation: true } : {}),
252
200
  ...(candidate.alwaysRequiresApproval
253
201
  ? { alwaysRequiresApproval: true }
254
202
  : {}),
203
+ ...(candidate.unattendedExecution
204
+ ? {
205
+ unattendedExecution: {
206
+ capability: candidate.unattendedExecution.capability,
207
+ operation: candidate.unattendedExecution.operation,
208
+ objectConstrained:
209
+ candidate.unattendedExecution.objectForInput !== undefined,
210
+ },
211
+ }
212
+ : {}),
255
213
  ...(candidate.deferLoading ? { deferLoading: true } : {}),
256
214
  ...(candidate.source ? { source: candidate.source } : {}),
257
215
  retry: piToolRetryPolicy(candidate),
@@ -267,10 +225,25 @@ function describeRuntime(
267
225
  candidates: readonly PiToolCandidate[],
268
226
  loadedExtensions: readonly PiLoadedExtension[],
269
227
  ): string {
228
+ const model = snapshot.pi.model;
229
+ const openRouterRouting = model.compat && "openRouterRouting" in model.compat
230
+ ? model.compat.openRouterRouting
231
+ : undefined;
270
232
  return JSON.stringify({
271
233
  version: 1,
272
- model: snapshot.pi.model.id,
273
- provider: snapshot.pi.model.provider,
234
+ model: model.id,
235
+ provider: model.provider,
236
+ modelConfig: {
237
+ api: model.api,
238
+ name: model.name,
239
+ reasoning: model.reasoning,
240
+ input: model.input,
241
+ contextWindow: model.contextWindow,
242
+ maxTokens: model.maxTokens,
243
+ cost: model.cost,
244
+ ...(model.thinkingLevelMap ? { thinkingLevelMap: model.thinkingLevelMap } : {}),
245
+ ...(openRouterRouting ? { openRouterRouting } : {}),
246
+ },
274
247
  thinking: snapshot.pi.thinkingLevel,
275
248
  systemPrompt: snapshot.pi.systemPrompt,
276
249
  executionLevel: snapshot.profile.executionLevel,
@@ -314,7 +287,7 @@ class PreparedRuntime implements PreparedPiRuntime {
314
287
  ) {}
315
288
 
316
289
  // 在调用方证明适配器身份后返回内部准备状态。
317
- // readPreparedPiRuntime 在固定配置或创建 Turn 前调用它。
290
+ // readPreparedPiRuntime 在创建 Turn 前调用它。
318
291
  // 公开接口没有可信的来源字段,所以这里必须比较对象身份。
319
292
  read(owner: object): PreparedPiRuntimeState {
320
293
  if (owner !== this.owner) {
@@ -330,7 +303,7 @@ class PreparedRuntime implements PreparedPiRuntime {
330
303
  * 为创建它的 HarnessRuntimeConfig 打开准备句柄。
331
304
  *
332
305
  * @remarks
333
- * 固定配置和创建 Turn 都会先调用它,再读取快照、装配结果或工具候选。
306
+ * 创建 Turn 前调用它,读取快照、装配结果或工具候选。
334
307
  *
335
308
  * 具体类检查与 owner 检查一起拒绝伪造句柄和跨适配器复用。
336
309
  */
@@ -344,42 +317,6 @@ export function readPreparedPiRuntime(
344
317
  return prepared.read(owner);
345
318
  }
346
319
 
347
- /**
348
- * 读取已存的固定描述。
349
- *
350
- * @remarks
351
- * `HarnessRuntimeConfig.harnessInputs` 在新建或恢复 Pi operation 前调用它。
352
- *
353
- * Prepared Runtime 提供当前执行能力,descriptor 仅保留 Submission 固定的 Turn 字段。
354
- */
355
- export function readPinnedPiRuntime(
356
- prepared: PreparedPiRuntime,
357
- owner: object,
358
- descriptorBody: string,
359
- ): {
360
- readonly state: PreparedPiRuntimeState;
361
- readonly descriptor: PinnedPiRuntimeDescriptor;
362
- } {
363
- const state = readPreparedPiRuntime(prepared, owner);
364
- let value: unknown;
365
- try {
366
- value = JSON.parse(descriptorBody);
367
- } catch {
368
- throw new Error("Pinned Runtime assembly descriptor is invalid");
369
- }
370
- if (!value || typeof value !== "object") {
371
- throw new Error("Pinned Runtime assembly descriptor is invalid");
372
- }
373
- const descriptor = value as PinnedPiRuntimeDescriptor;
374
- if (
375
- descriptor.version !== 1 ||
376
- typeof descriptor.systemPrompt !== "string"
377
- ) {
378
- throw new Error("Pinned Runtime assembly descriptor is invalid");
379
- }
380
- return { state, descriptor };
381
- }
382
-
383
320
  // #endregion
384
321
 
385
322
  // #region 扩展与工具装配
@@ -431,7 +368,7 @@ async function preparePiAssembly(
431
368
 
432
369
  // #endregion
433
370
 
434
- // #region Runtime 准备与提交固定
371
+ // #region Runtime 准备与当前上下文
435
372
 
436
373
  /**
437
374
  * 为一份已校验的 Runtime 快照准备扩展和工具状态。
@@ -468,34 +405,33 @@ export async function preparePiRuntime(
468
405
  }
469
406
 
470
407
  /**
471
- * 把请求时的上下文和执行档位固定到一次提交的描述中。
408
+ * 从当前 Runtime 装配模型要用的系统上下文。
472
409
  *
473
410
  * @remarks
474
- * Runtime 在持久化提交并启动 Turn 前的准入阶段调用它。
411
+ * Runtime 每次打开或恢复 Harness 前调用它。
475
412
  *
476
- * 此时重建上下文可避免把动态记忆和扩展上下文写进 Pi 消息,同时让恢复继续使用已准入的结果。
413
+ * 重新读取动态记忆和扩展上下文,不从旧 Submission 描述恢复配置。
477
414
  */
478
- export async function pinPiRuntime(
479
- options: PinPiRuntimeOptions,
415
+ export async function assembleCurrentPiContext(
416
+ options: CurrentPiContextOptions,
480
417
  owner: object,
481
- ): Promise<PinnedPiRuntime> {
418
+ ): Promise<{ systemPrompt: string; degradations: readonly RuntimeDegradation[] }> {
482
419
  const state = readPreparedPiRuntime(options.prepared, owner);
483
420
  const { snapshot, assembly } = state;
421
+ const includeMemory = options.includeMemory !== false;
484
422
  const context = await assemblePiSystemContext({
485
423
  baseSystemPrompt: snapshot.pi.systemPrompt,
486
- memory: snapshot.profile.memory,
487
- memoryPort: snapshot.bindings.memory,
488
- workspace: snapshot.bindings.workspace,
424
+ memory: includeMemory
425
+ ? snapshot.profile.memory
426
+ : { ...snapshot.profile.memory, enabled: false },
427
+ memoryPort: includeMemory ? snapshot.bindings.memory : undefined,
428
+ workspace: includeMemory ? snapshot.bindings.workspace : undefined,
489
429
  skills: snapshot.bindings.skills.sources,
490
430
  extensionContexts: assembly.context,
491
431
  readExtensionContext: options.readExtensionContext,
492
432
  });
493
433
  return Object.freeze({
494
- descriptor: JSON.stringify({
495
- ...JSON.parse(options.prepared.revisionDescriptor),
496
- systemPrompt: context.systemPrompt,
497
- baseRevision: options.baseRevision,
498
- }),
434
+ systemPrompt: context.systemPrompt,
499
435
  degradations: context.degradations,
500
436
  });
501
437
  }
@@ -17,7 +17,7 @@ export * from "../conversation/message";
17
17
  export * from "../submission/contracts";
18
18
  export * from "../conversation/state";
19
19
  export * from "../lib/execution-level";
20
- export type { WorkspaceRevision, WorkspaceRevisionManifest } from "../tools/workspace-versioning";
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 "../tools/subagent-authority";
30
+ } from "../tools/subagent/authority";
@@ -1,4 +1,5 @@
1
1
  export interface RuntimeConfigUpdateResult<Change> {
2
2
  readonly change: Change;
3
- readonly runtime: "unchanged" | "reloaded" | "reload-failed";
3
+ /** Deferred changes are persisted but activated at the next execution slice. */
4
+ readonly runtime: "unchanged" | "reloaded" | "deferred" | "reload-failed";
4
5
  }
@@ -1,4 +1,4 @@
1
- import { estimateStringTokens } from "agents/experimental/memory/utils";
1
+ import { estimateStringTokens } from "../lib/token-estimate";
2
2
  import type { RuntimeMemoryPort } from "../config/ports";
3
3
  import type { RuntimeDegradation } from "../config/degradation";
4
4
  import type { RuntimeMemoryProfile } from "../config/profile";
@@ -12,8 +12,8 @@ import type {
12
12
  import type { RuntimeDegradation } from "../../config/degradation";
13
13
  import { withRuntimeLoadTimeout } from "../../config/runtime-load";
14
14
  import { sanitizeExtensionName } from "../../lib/extension-name";
15
- import type { PiToolCandidate } from "../../tools/compiler";
16
- import { createPiDeclaredToolCandidate } from "../../tools/declared";
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-sandbox.ts` 的 `READ_PAGE_MAX_CHARS`),
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;
@@ -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: new TextEncoder().encode(text).byteLength,
168
- hash: hash.slice(0, 16),
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 会返回