@springbrand/agent-runtime 0.1.0

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 (75) hide show
  1. package/package.json +28 -0
  2. package/src/db/approval.repo.ts +291 -0
  3. package/src/db/ext-context.repo.ts +34 -0
  4. package/src/db/index.ts +83 -0
  5. package/src/db/message-ui.repo.ts +39 -0
  6. package/src/db/milestone.repo.ts +96 -0
  7. package/src/db/runtime-event-outbox.repo.ts +89 -0
  8. package/src/db/schema.ts +164 -0
  9. package/src/db/settlement.repo.ts +104 -0
  10. package/src/db/steer.repo.ts +73 -0
  11. package/src/db/submission.repo.ts +323 -0
  12. package/src/index.ts +133 -0
  13. package/src/kernel/approval-lifecycle.ts +552 -0
  14. package/src/kernel/bindings.ts +898 -0
  15. package/src/kernel/degradation.ts +15 -0
  16. package/src/kernel/extensions.ts +108 -0
  17. package/src/kernel/profile.ts +116 -0
  18. package/src/kernel/public-contracts.ts +17 -0
  19. package/src/kernel/receipts.ts +124 -0
  20. package/src/kernel/recoverable-chat-agent.ts +899 -0
  21. package/src/kernel/state.ts +76 -0
  22. package/src/kernel/submission-lifecycle.ts +600 -0
  23. package/src/layers/context/budget/gate.ts +88 -0
  24. package/src/layers/orchestration/subagents/agent-types/contract.ts +78 -0
  25. package/src/layers/orchestration/subagents/agent-types/extract/index.ts +47 -0
  26. package/src/layers/orchestration/subagents/agent-types/fanout/index.ts +53 -0
  27. package/src/layers/orchestration/subagents/agent-types/registry.ts +16 -0
  28. package/src/layers/orchestration/temporary-agent/core.ts +152 -0
  29. package/src/layers/orchestration/temporary-agent/runner.ts +133 -0
  30. package/src/layers/orchestration/temporary-agent/workspace.ts +154 -0
  31. package/src/lib/artifacts.ts +54 -0
  32. package/src/lib/egress.ts +44 -0
  33. package/src/lib/execution-level.ts +27 -0
  34. package/src/lib/extension-name.ts +18 -0
  35. package/src/lib/host-actions.ts +57 -0
  36. package/src/lib/mcp.ts +86 -0
  37. package/src/lib/model-catalog.ts +7 -0
  38. package/src/lib/prompt.ts +139 -0
  39. package/src/lib/telemetry-dev.ts +44 -0
  40. package/src/pi/assembly/context.ts +510 -0
  41. package/src/pi/assembly/extensions.ts +661 -0
  42. package/src/pi/assembly/index.ts +19 -0
  43. package/src/pi/assembly/snapshot.ts +200 -0
  44. package/src/pi/message/contract.ts +8 -0
  45. package/src/pi/message/conversion.ts +73 -0
  46. package/src/pi/message/index.ts +3 -0
  47. package/src/pi/message/projection.ts +604 -0
  48. package/src/pi/runtime-adapter/assembly.ts +552 -0
  49. package/src/pi/runtime-adapter/execution.ts +683 -0
  50. package/src/pi/runtime-adapter/index.ts +232 -0
  51. package/src/pi/runtime-adapter/models.ts +243 -0
  52. package/src/pi/runtime-adapter/recovery.ts +805 -0
  53. package/src/pi/runtime-adapter/transcript.ts +825 -0
  54. package/src/pi/session/index.ts +24 -0
  55. package/src/pi/session/storage.ts +353 -0
  56. package/src/pi/tool/ai-adapter.ts +100 -0
  57. package/src/pi/tool/base.ts +110 -0
  58. package/src/pi/tool/compiler.ts +444 -0
  59. package/src/pi/tool/core-host.ts +48 -0
  60. package/src/pi/tool/core.ts +251 -0
  61. package/src/pi/tool/index.ts +32 -0
  62. package/src/pi/tool/mcp.ts +319 -0
  63. package/src/pi/tool/schedule.ts +198 -0
  64. package/src/pi/tool/skill.ts +455 -0
  65. package/src/pi/tool/subagent.ts +148 -0
  66. package/src/pi/tool/web-search/api.ts +1292 -0
  67. package/src/pi/tool/web-search/index.ts +2 -0
  68. package/src/pi/tool/web-search/web-search.ts +127 -0
  69. package/src/pi/tool/workspace-sandbox.ts +664 -0
  70. package/src/pi/turn/approval.ts +181 -0
  71. package/src/pi/turn/index.ts +62 -0
  72. package/src/pi/turn/tool-recovery.ts +792 -0
  73. package/src/plugins.ts +1024 -0
  74. package/src/runtime-agent.ts +654 -0
  75. package/src/runtime.ts +2880 -0
@@ -0,0 +1,898 @@
1
+ import type { SkillSource } from "agents/skills";
2
+ import type { ScheduleSpec } from "./receipts";
3
+ import type { RuntimeActivityProjection } from "./state";
4
+ import type { ExecutionLevel } from "../lib/execution-level";
5
+
6
+ // #region Workspace 端口
7
+
8
+ /**
9
+ * 描述 Workspace 中一个目录项的当前元数据。
10
+ *
11
+ * @remarks
12
+ * Workspace 实现在 `stat`、`lstat`、`readDir` 和 `glob` 返回它。
13
+ *
14
+ * Runtime 只依赖这个窄投影,核心术语见 `../index.ts`。
15
+ */
16
+ export interface WorkspaceFileInfo {
17
+ path: string;
18
+ name: string;
19
+ type: "file" | "directory" | "symlink";
20
+ mimeType: string;
21
+ size: number;
22
+ createdAt: number;
23
+ updatedAt: number;
24
+ target?: string;
25
+ }
26
+
27
+ /**
28
+ * 向 Runtime 提供已限定作用域的文件操作。
29
+ *
30
+ * @remarks
31
+ * Workspace 工具、记忆组装和 Host RPC 在读写当前会话文件时调用它。
32
+ *
33
+ * Host 负责路径隔离、配额和持久化;Runtime 不得绕过该 Port 接触底层存储。
34
+ */
35
+ export interface WorkspacePort {
36
+ /**
37
+ * 把文本文件读成字符串,文件不存在时返回 `null`。
38
+ *
39
+ * @remarks
40
+ * Workspace 工具、记忆组装或 Host 文件 RPC 在需要文本内容时调用。
41
+ *
42
+ * 缺失用 `null` 表示,让调用方能区分“没有文件”与存储故障。
43
+ */
44
+ readFile(path: string): Promise<string | null>;
45
+ /**
46
+ * 把文件读成原始字节,文件不存在时返回 `null`。
47
+ *
48
+ * @remarks
49
+ * 需要保留二进制内容的 Workspace 或 Sandbox 边界调用它。
50
+ *
51
+ * 它与 `readFile` 分开,避免 Runtime 猜测字符编码。
52
+ */
53
+ readFileBytes(path: string): Promise<Uint8Array | null>;
54
+ /**
55
+ * 覆盖写入一个文本文件。
56
+ *
57
+ * @remarks
58
+ * Workspace 工具、记忆服务和 Host RPC 在提交完整文本时调用,并可传入 MIME 类型。
59
+ *
60
+ * 写入语义由 Host 统一实现,便于在一个边界内做作用域与配额检查。
61
+ */
62
+ writeFile(path: string, content: string, mimeType?: string): Promise<void>;
63
+ /**
64
+ * 覆盖写入一个二进制文件。
65
+ *
66
+ * @remarks
67
+ * Workspace 或 Sandbox 边界在提交原始字节时调用,并可传入 MIME 类型。
68
+ *
69
+ * 接受 `Uint8Array` 和 `ArrayBuffer` 是为了直接承接当前调用方,不在 Runtime 内复制或转码。
70
+ */
71
+ writeFileBytes(
72
+ path: string,
73
+ data: Uint8Array | ArrayBuffer,
74
+ mimeType?: string,
75
+ ): Promise<void>;
76
+ /**
77
+ * 把文本追加到文件末尾。
78
+ *
79
+ * @remarks
80
+ * 需要增量记录内容的 Workspace 调用方使用它,并可传入 MIME 类型。
81
+ *
82
+ * 追加由 Host 实现,避免 Runtime 通过先读后写制造丢更新窗口。
83
+ */
84
+ appendFile(path: string, content: string, mimeType?: string): Promise<void>;
85
+ /**
86
+ * 判断一个 Workspace 路径是否存在。
87
+ *
88
+ * @remarks
89
+ * 需要分支处理缺失路径的 Workspace 或 Host 逻辑在操作前调用。
90
+ *
91
+ * 存在性查询保留在 Port 内,让作用域映射与实际访问使用同一套规则。
92
+ */
93
+ exists(path: string): Promise<boolean>;
94
+ /**
95
+ * 读取路径指向目标的元数据。
96
+ *
97
+ * @remarks
98
+ * Workspace 工具和 Host 计量逻辑在需要文件类型、大小或时间时调用。
99
+ *
100
+ * 实现可以解析最终目标;需要检查符号链接本身时应改用 `lstat`。
101
+ */
102
+ stat(path: string): Promise<WorkspaceFileInfo | null>;
103
+ /**
104
+ * 读取路径项本身的元数据。
105
+ *
106
+ * @remarks
107
+ * 作用域安全检查在识别路径中的符号链接时调用。
108
+ *
109
+ * 它不与 `stat` 合并,因为跟随符号链接会破坏当前的边界检查。
110
+ */
111
+ lstat(path: string): Promise<WorkspaceFileInfo | null>;
112
+ /**
113
+ * 创建一个 Workspace 目录。
114
+ *
115
+ * @remarks
116
+ * Workspace 工具、记忆服务或 Host 初始化逻辑在写入目录树前调用。
117
+ *
118
+ * `recursive` 透传给 Host,Runtime 不自行拆成多次非原子调用。
119
+ */
120
+ mkdir(path: string, opts?: { recursive?: boolean }): Promise<void>;
121
+ /**
122
+ * 按页列出一个 Workspace 目录的直接内容。
123
+ *
124
+ * @remarks
125
+ * Workspace 工具、Host RPC 和用量扫描在枚举目录时调用;省略 `dir` 表示当前根目录。
126
+ *
127
+ * 端口保留 `limit` 和 `offset`,避免大目录被强制一次载入。
128
+ */
129
+ readDir(
130
+ dir?: string,
131
+ opts?: { limit?: number; offset?: number },
132
+ ): Promise<WorkspaceFileInfo[]>;
133
+ /**
134
+ * 删除一个 Workspace 路径。
135
+ *
136
+ * @remarks
137
+ * Workspace 删除工具或 Host RPC 在用户明确请求删除时调用。
138
+ *
139
+ * `recursive` 和 `force` 由 Host 按存储语义执行,根目录与作用域保护也必须留在 Host。
140
+ */
141
+ rm(path: string, opts?: { recursive?: boolean; force?: boolean }): Promise<void>;
142
+ /**
143
+ * 在 Workspace 内复制文件或目录。
144
+ *
145
+ * @remarks
146
+ * Workspace 工具在需要保留原件时调用,复制目录时显式传入 `recursive`。
147
+ *
148
+ * 源和目标都经过同一 Port,让 Host 能在一处强制路径边界。
149
+ */
150
+ cp(src: string, dest: string, opts?: { recursive?: boolean }): Promise<void>;
151
+ /**
152
+ * 在 Workspace 内移动或重命名文件与目录。
153
+ *
154
+ * @remarks
155
+ * Workspace 工具在不再保留原路径时调用,移动目录时显式传入 `recursive`。
156
+ *
157
+ * 由 Host 执行移动,避免 Runtime 用“复制后删除”造成部分成功。
158
+ */
159
+ mv(src: string, dest: string, opts?: { recursive?: boolean }): Promise<void>;
160
+ /**
161
+ * 在 Workspace 中创建一个符号链接。
162
+ *
163
+ * @remarks
164
+ * 只有允许符号链接的 Workspace 实现才应接受该调用;当前会话作用域实现会拒绝它。
165
+ *
166
+ * 权限决定留给 Host,因为链接解析会直接影响作用域隔离。
167
+ */
168
+ symlink(target: string, linkPath: string): Promise<void>;
169
+ /**
170
+ * 读取一个符号链接保存的目标。
171
+ *
172
+ * @remarks
173
+ * Workspace 调用方在已知路径是符号链接且需要显示目标时调用。
174
+ *
175
+ * 返回值仍经 Host 投影,避免泄露底层物理 Workspace 路径。
176
+ */
177
+ readlink(path: string): Promise<string>;
178
+ /**
179
+ * 按模式查找 Workspace 目录项。
180
+ *
181
+ * @remarks
182
+ * Workspace 搜索工具在路径模式已明确时调用。
183
+ *
184
+ * 匹配与作用域投影交给 Host,Runtime 不先枚举全部文件再自行过滤。
185
+ */
186
+ glob(pattern: string): Promise<WorkspaceFileInfo[]>;
187
+ }
188
+
189
+ /**
190
+ * 汇总一个已限定作用域的 Workspace 用量。
191
+ *
192
+ * @remarks
193
+ * Host 管理面在展示或检查当前会话用量时使用它。
194
+ *
195
+ * Runtime 不自行计数,因为计费边界由 Host 的作用域决定。
196
+ */
197
+ export interface WorkspaceUsage {
198
+ fileCount: number;
199
+ directoryCount: number;
200
+ totalBytes: number;
201
+ }
202
+
203
+ /**
204
+ * 说明一个 Workspace 作用域的持久存储配额。
205
+ *
206
+ * @remarks
207
+ * Host 管理面在返回 Workspace 限额时使用,`null` 表示 Host 未配置该项。
208
+ *
209
+ * HTTP 上传大小等传输限制不属于这组持久存储配额,不能混用。
210
+ */
211
+ export interface WorkspaceQuota {
212
+ maxFiles: number | null;
213
+ maxTotalBytes: number | null;
214
+ maxFileBytes: number | null;
215
+ }
216
+
217
+ /**
218
+ * 向 Host 提供一个已限定作用域 Workspace 的生命周期和计量操作。
219
+ *
220
+ * @remarks
221
+ * Inbox 等可信 Host 代码在创建、查询或清理会话 Workspace 时调用它。
222
+ *
223
+ * 它故意不继承 `WorkspacePort`,防止 Runtime 通过数据面引用取得管理能力。
224
+ */
225
+ export interface WorkspaceAdminPort {
226
+ /**
227
+ * 确保当前作用域所需的 Workspace 目录已存在。
228
+ *
229
+ * @remarks
230
+ * Host 在会话初始化或首次使用 Workspace 前调用。
231
+ *
232
+ * 初始化留在管理面,不让 Runtime 知道物理目录布局。
233
+ */
234
+ ensure(): Promise<void>;
235
+ /**
236
+ * 统计当前 Workspace 作用域的持久存储用量。
237
+ *
238
+ * @remarks
239
+ * Host 在展示用量或执行配额相关检查时调用。
240
+ *
241
+ * 实现负责排除不应归属当前作用域的共享数据。
242
+ */
243
+ getUsage(): Promise<WorkspaceUsage>;
244
+ /**
245
+ * 返回当前 Workspace 作用域的持久存储配额。
246
+ *
247
+ * @remarks
248
+ * Host 在响应配额查询时调用。
249
+ *
250
+ * 配额由 Host 配置与解释,Runtime 只接收数据面能力。
251
+ */
252
+ getQuota(): Promise<WorkspaceQuota>;
253
+ /**
254
+ * 删除当前 Workspace 作用域的全部私有数据。
255
+ *
256
+ * @remarks
257
+ * Host 仅在清理或删除对应会话时调用。
258
+ *
259
+ * 该危险操作不暴露给 Runtime,并必须由实现保护用户级共享目录。
260
+ */
261
+ removeAll(): Promise<void>;
262
+ }
263
+
264
+ /**
265
+ * 读写当前 Agent 与会话范围内的热记忆块。
266
+ *
267
+ * @remarks
268
+ * Memory Plugin 在装配时绑定它,Runtime 在生成 Turn 系统上下文时读取。
269
+ *
270
+ * 作用域与存储细节留给 Host,核心术语见 `../index.ts`。
271
+ */
272
+ export interface RuntimeMemoryPort {
273
+ /**
274
+ * 按标签读取一块热记忆,不存在时返回 `null`。
275
+ *
276
+ * @remarks
277
+ * Pi 系统上下文组装在 Turn 开始前读取 `memory` 和 `preferences`。
278
+ *
279
+ * 标签查询由 Host 限定到当前 Agent 与会话,Runtime 不携带业务 ID。
280
+ */
281
+ get(label: string): Promise<string | null>;
282
+ /**
283
+ * 按标签覆盖一块热记忆。
284
+ *
285
+ * @remarks
286
+ * Host 实现提供该能力,但当前 `packages/agent-runtime/src` 没有调用点。
287
+ *
288
+ * TODO(待确认): 确认后续写入方是否仍需通过这个公开 Port 提交热记忆。
289
+ */
290
+ set(label: string, content: string): Promise<void>;
291
+ }
292
+
293
+ // #endregion
294
+
295
+ // #region Sandbox 端口
296
+
297
+ /**
298
+ * 描述一次前台 Sandbox 命令。
299
+ *
300
+ * @remarks
301
+ * `sandbox_exec` 工具在执行前组装它,Host Adapter 负责校验目录与超时。
302
+ *
303
+ * 它只传输执行所需的最小字段,不暴露 Sandbox SDK 对象。
304
+ */
305
+ export interface SandboxExecInput {
306
+ command: string;
307
+ cwd?: string;
308
+ stdin?: string;
309
+ timeoutMs?: number;
310
+ }
311
+
312
+ /**
313
+ * 描述一次后台 Sandbox 进程启动。
314
+ *
315
+ * @remarks
316
+ * `sandbox_start_process` 工具在启动长运行进程前组装它。
317
+ *
318
+ * 进程生命周期由 Host Adapter 管理,因此输入不携带 SDK 会话对象。
319
+ */
320
+ export interface SandboxStartProcessInput {
321
+ command: string;
322
+ cwd?: string;
323
+ stdin?: string;
324
+ }
325
+
326
+ /**
327
+ * 返回一次前台 Sandbox 命令的有界输出。
328
+ *
329
+ * @remarks
330
+ * `sandbox_exec` 工具在命令完成后将它投影给模型。
331
+ *
332
+ * 截断标记必须与文本一起返回,让调用方不会把不完整输出当成全量结果。
333
+ */
334
+ export interface SandboxExecResult {
335
+ success: boolean;
336
+ stdout: string;
337
+ stderr: string;
338
+ exitCode: number;
339
+ stdoutTruncated: boolean;
340
+ stderrTruncated: boolean;
341
+ }
342
+
343
+ /**
344
+ * 描述一个 Sandbox 后台进程的当前状态。
345
+ *
346
+ * @remarks
347
+ * 启动进程或后续查询时,Sandbox 工具用它向模型返回稳定投影。
348
+ *
349
+ * Runtime 不暴露提供商进程对象,避免 SDK 类型越过 Port 边界。
350
+ */
351
+ export interface SandboxProcessSummary {
352
+ id: string;
353
+ command: string;
354
+ status: string;
355
+ exitCode?: number;
356
+ }
357
+
358
+ /**
359
+ * 返回一个 Sandbox 后台进程的有界日志。
360
+ *
361
+ * @remarks
362
+ * `sandbox_process_logs` 工具按进程 ID 查询时使用它。
363
+ *
364
+ * stdout 和 stderr 分开且携带截断标记,避免丢失命令的错误语义。
365
+ */
366
+ export interface SandboxProcessLogs {
367
+ id: string;
368
+ stdout: string;
369
+ stderr: string;
370
+ stdoutTruncated: boolean;
371
+ stderrTruncated: boolean;
372
+ }
373
+
374
+ /**
375
+ * 描述一个没有发布成功的 Sandbox 文件。
376
+ *
377
+ * @remarks
378
+ * Sandbox Adapter 在批量发布回 Workspace 时为每个失败项生成它。
379
+ *
380
+ * 按文件保留错误码,让部分成功不需被折叠成一个模糊异常。
381
+ */
382
+ export interface SandboxSyncFailure {
383
+ path: string;
384
+ errorCode: string;
385
+ }
386
+
387
+ /**
388
+ * 汇总 Sandbox 文件发布回 Workspace 的结果。
389
+ *
390
+ * @remarks
391
+ * `sandbox_publish_files` 工具在显式持久化文件后把它返回给模型。
392
+ *
393
+ * 成功、跳过和失败分开记录,因为一次批量发布可以部分成功。
394
+ */
395
+ export interface SandboxSyncResult {
396
+ files: readonly string[];
397
+ skipped: readonly string[];
398
+ failed: readonly SandboxSyncFailure[];
399
+ bytes: number;
400
+ }
401
+
402
+ /**
403
+ * 列出 Runtime 能稳定识别的 Sandbox 失败类别。
404
+ *
405
+ * @remarks
406
+ * Host Adapter 在映射提供商异常时使用,工具层可据此返回一致错误。
407
+ *
408
+ * 该联合类型是 Port 协议;改名或删除值会破坏 Host 映射与调用方分支。
409
+ */
410
+ export type SandboxErrorCode =
411
+ | "capacity_unavailable"
412
+ | "startup_failed"
413
+ | "workspace_hydration_failed"
414
+ | "timeout"
415
+ | "not_found"
416
+ | "invalid_path"
417
+ | "output_limit_exceeded"
418
+ | "rate_limited"
419
+ | "concurrency_limited"
420
+ | "publish_too_large"
421
+ | "publish_limit_exceeded"
422
+ | "workspace_conflict"
423
+ | "operation_failed";
424
+
425
+ /**
426
+ * 把 Sandbox 失败作为与提供商无关的 Port 异常抛出。
427
+ *
428
+ * @remarks
429
+ * Host Adapter 在命令、进程或发布失败时构造它,Runtime 和 E2E 调用方可检查 `code`。
430
+ *
431
+ * 错误消息同时携带固定前缀与结构化代码,保留日志可读性和程序分支能力。
432
+ */
433
+ export class SandboxPortError extends Error {
434
+ /**
435
+ * 创建一个带稳定错误码的 Sandbox Port 异常。
436
+ *
437
+ * @remarks
438
+ * Sandbox Adapter 在把 SDK 或策略失败转换到 Runtime 边界时调用。
439
+ *
440
+ * 构造器统一设置前缀和 `name`,不应由每个抛出点重复拼接。
441
+ */
442
+ constructor(
443
+ readonly code: SandboxErrorCode,
444
+ message: string,
445
+ ) {
446
+ super(`sandbox_error:${code}:${message}`);
447
+ this.name = "SandboxPortError";
448
+ }
449
+ }
450
+
451
+ /**
452
+ * 向 Runtime 工具提供隔离的 Linux Sandbox 执行与发布能力。
453
+ *
454
+ * @remarks
455
+ * Sandbox Plugin 在装配时把它交给 Sandbox 工具候选,工具在 Turn 内调用。
456
+ *
457
+ * 命令限制、工作目录校验、水合与冲突安全发布都留在 Host Adapter;术语见 `../index.ts`。
458
+ */
459
+ export interface RuntimeSandboxPort {
460
+ /**
461
+ * 在 Sandbox 前台执行一条命令并等待完成。
462
+ *
463
+ * @remarks
464
+ * `sandbox_exec` 工具在用户 Turn 内调用,并把 Turn 的取消信号传入。
465
+ *
466
+ * 超时、输出上限和 Workspace 水合由 Adapter 统一执行,不在工具层复制。
467
+ */
468
+ exec(
469
+ input: SandboxExecInput,
470
+ signal?: AbortSignal,
471
+ ): Promise<SandboxExecResult>;
472
+ /**
473
+ * 在 Sandbox 中启动一个后台进程。
474
+ *
475
+ * @remarks
476
+ * `sandbox_start_process` 工具在需要长时间运行的命令时调用,后续用返回的 ID 查日志或停止。
477
+ *
478
+ * 进程上限、命名和清理属于 Host 策略,Runtime 只依赖稳定摘要。
479
+ */
480
+ startProcess(
481
+ input: SandboxStartProcessInput,
482
+ ): Promise<SandboxProcessSummary>;
483
+ /**
484
+ * 读取一个 Sandbox 后台进程的有界日志。
485
+ *
486
+ * @remarks
487
+ * `sandbox_process_logs` 工具在拿到进程 ID 后按需调用。
488
+ *
489
+ * Adapter 负责验证 ID 归属和截断输出,避免工具越过当前 Sandbox 作用域。
490
+ */
491
+ getProcessLogs(id: string): Promise<SandboxProcessLogs>;
492
+ /**
493
+ * 停止一个 Sandbox 后台进程。
494
+ *
495
+ * @remarks
496
+ * `sandbox_stop_process` 工具在用户或模型明确要求结束进程时调用。
497
+ *
498
+ * 返回 `{ stopped: false }` 而不必然抛错,让“进程已不在运行”与系统故障分开。
499
+ */
500
+ stopProcess(id: string): Promise<{ stopped: boolean }>;
501
+ /**
502
+ * 把选定的 Sandbox 文件显式发布回持久 Workspace。
503
+ *
504
+ * @remarks
505
+ * `sandbox_publish_files` 工具仅在需要保留临时 Sandbox 产物时调用。
506
+ *
507
+ * 发布不与命令执行自动绑定,避免失败或未确认的临时文件污染持久 Workspace。
508
+ */
509
+ publishFiles(paths: readonly string[]): Promise<SandboxSyncResult>;
510
+ }
511
+
512
+ // #endregion
513
+
514
+ // #region Runtime 服务端口
515
+
516
+ /**
517
+ * 描述一条模型可见的定时任务。
518
+ *
519
+ * @remarks
520
+ * `list_schedules` 工具在用户查询或取消任务前展示它。
521
+ *
522
+ * 这是窄投影,故意不携带归属、历史等 Host 管理面字段。
523
+ */
524
+ export interface RuntimeScheduleSummary {
525
+ id: string;
526
+ label?: string;
527
+ /** 人读的触发描述,如 `cron 0 9 * * *`、`每 3600 秒`或`一次性`。 */
528
+ trigger: string;
529
+ tz: string;
530
+ nextRun: number | null;
531
+ enabled: boolean;
532
+ status: "active" | "paused" | "completed" | "error_paused";
533
+ prompt: string;
534
+ }
535
+
536
+ export interface RuntimeScheduleUpdate {
537
+ trigger?: ScheduleSpec["trigger"];
538
+ prompt?: string;
539
+ label?: string;
540
+ tz?: string;
541
+ }
542
+
543
+ /**
544
+ * 让 Runtime 通过 Host 管理当前用户的定时任务。
545
+ *
546
+ * @remarks
547
+ * Schedule Plugin 在装配时把它交给基础工具,模型在用户要求创建、查询或取消时调用。
548
+ *
549
+ * 任务归属和持久化留在 Host,Runtime 只传递 `ScheduleSpec` 和窄结果。
550
+ */
551
+ export interface RuntimeSchedulePort {
552
+ /**
553
+ * 创建一条定时任务并返回它的 ID。
554
+ *
555
+ * @remarks
556
+ * `schedule` 工具在把用户的时间与提示词组成 `ScheduleSpec` 后调用。
557
+ *
558
+ * Host 在该边界内绑定用户与会话,Runtime 不携带业务归属 ID。
559
+ */
560
+ create(spec: ScheduleSpec): Promise<{ id: string }>;
561
+ /**
562
+ * 列出当前用户的定时任务。
563
+ *
564
+ * @remarks
565
+ * `list_schedules` 工具在用户查询任务或取消前查找 ID 时调用。
566
+ *
567
+ * 模型必须能查询已创建任务,否则用户无法在对话中可靠地管理它们。
568
+ */
569
+ list(): Promise<RuntimeScheduleSummary[]>;
570
+ update(
571
+ id: string,
572
+ changes: RuntimeScheduleUpdate,
573
+ ): Promise<{ ok: boolean }>;
574
+ pause(id: string): Promise<{ ok: boolean }>;
575
+ resume(id: string): Promise<{ ok: boolean }>;
576
+ /**
577
+ * 按 ID 取消一条定时任务。
578
+ *
579
+ * @remarks
580
+ * `cancel_schedule` 工具先列出任务并确定目标后调用。
581
+ *
582
+ * 不存在的 ID 用 `{ ok: false }` 表示,与 Host 运行故障的异常分开。
583
+ */
584
+ cancel(id: string): Promise<{ ok: boolean }>;
585
+ }
586
+
587
+ /**
588
+ * 表示一次 Subagent 运行的完成或非完成结果。
589
+ *
590
+ * @remarks
591
+ * Subagent 工具在 Host 返回运行状态后用它决定输出正常结果还是失败投影。
592
+ *
593
+ * `completed` 分支必须携带 `output`,其他状态保留 Host 返回的字符串。
594
+ */
595
+ export type RuntimeSubagentRunResult =
596
+ | {
597
+ status: "completed";
598
+ runId: string;
599
+ output: unknown;
600
+ error?: undefined;
601
+ }
602
+ | {
603
+ status: string;
604
+ runId: string;
605
+ output?: unknown;
606
+ error?: string;
607
+ };
608
+
609
+ /**
610
+ * 让 Runtime 通过 Host 启动已授权的 Subagent。
611
+ *
612
+ * @remarks
613
+ * Subagent Plugin 在装配时把它交给启用的 Subagent 工具,工具在 Turn 内调用。
614
+ *
615
+ * 运行记录、后台通知和实际 Agent 路由由 Host 保持,Runtime 只传入类型与结构化输入。
616
+ */
617
+ export interface RuntimeSubagentPort {
618
+ /**
619
+ * 启动一次 Subagent 运行并返回当前结果。
620
+ *
621
+ * @remarks
622
+ * 同步 Subagent 工具直接调用;`dispatch_background` 会额外传入 `detached`、时间预算和通知来源。
623
+ *
624
+ * 可选项不拆成另一个方法,因为两种路径共用同一 Host 运行协议与 `runId`。
625
+ */
626
+ run(
627
+ agentType: string,
628
+ input: Readonly<Record<string, unknown>>,
629
+ options?: Readonly<{
630
+ detached?: boolean;
631
+ maxBudgetMs?: number;
632
+ notifySource?: string;
633
+ }>,
634
+ ): Promise<RuntimeSubagentRunResult>;
635
+ }
636
+
637
+ /**
638
+ * 投影一条 Turn 完成后的用户或助手文本消息。
639
+ *
640
+ * @remarks
641
+ * Runtime 在终态投影时从完整转录中提取这两种角色。
642
+ *
643
+ * 只保留角色与文本,避免 Host 投影端口依赖 Pi 的内部消息结构。
644
+ */
645
+ export interface RuntimeTurnMessage {
646
+ readonly role: "user" | "assistant";
647
+ readonly text: string;
648
+ }
649
+
650
+ export interface RuntimeModelUsageEvent {
651
+ readonly eventId: string;
652
+ readonly submissionId: string;
653
+ readonly kind: "assistant" | "compaction";
654
+ readonly api: string;
655
+ readonly provider: string;
656
+ readonly model: string;
657
+ readonly responseModel?: string;
658
+ readonly stopReason?: string;
659
+ readonly usage: {
660
+ readonly input: number;
661
+ readonly output: number;
662
+ readonly cacheRead: number;
663
+ readonly cacheWrite: number;
664
+ readonly cacheWrite1h?: number;
665
+ readonly reasoning?: number;
666
+ readonly totalTokens: number;
667
+ readonly cost: {
668
+ readonly input: number;
669
+ readonly output: number;
670
+ readonly cacheRead: number;
671
+ readonly cacheWrite: number;
672
+ readonly total: number;
673
+ };
674
+ };
675
+ }
676
+
677
+ export interface RuntimeToolSettlementEvent {
678
+ readonly eventId: string;
679
+ readonly submissionId: string;
680
+ readonly toolCallId: string;
681
+ readonly toolName: string;
682
+ readonly status: "success" | "error";
683
+ }
684
+
685
+ /**
686
+ * 把已持久化的 Turn 文本和逐步用量事件投影给 Host。
687
+ *
688
+ * @remarks
689
+ * `onResponse` 只在 Turn 终态后调用;用量回调在对应事实与
690
+ * durable outbox 同事务提交后调用。
691
+ *
692
+ * 一次传入当前文本投影,让 Host 保持唯一的后续写入顺序。
693
+ */
694
+ export interface RuntimeTurnEventsPort {
695
+ /**
696
+ * 把 Turn 终态的可见文本消息交给 Host。
697
+ *
698
+ * @remarks
699
+ * Runtime `projectTerminal` 在更新转录与客户端后调用;Host 实现应把它当作后续投影。
700
+ *
701
+ * Runtime 会捕获该回调的失败,避免应用投影反过来改写已完成 Turn 的结果。
702
+ */
703
+ onResponse(
704
+ messages: readonly RuntimeTurnMessage[],
705
+ ): Promise<void>;
706
+ /** 投递 Assistant 或 Compaction 的原始 provider usage。 */
707
+ onModelUsage?(event: RuntimeModelUsageEvent): Promise<void>;
708
+ /** 投递不含参数与结果的 Tool 最终结算事件。 */
709
+ onToolSettled?(event: RuntimeToolSettlementEvent): Promise<void>;
710
+ onApproval?(input: {
711
+ readonly submissionId: string;
712
+ readonly approvalExecutionId: string;
713
+ }): Promise<void>;
714
+ onActivityChanged?(
715
+ projection: RuntimeActivityProjection,
716
+ ): Promise<void>;
717
+ onSubmissionTerminal?(input: {
718
+ readonly submissionId: string;
719
+ readonly status: "completed" | "aborted" | "skipped" | "error";
720
+ readonly error?: string;
721
+ readonly resultMessageId?: string;
722
+ }): Promise<void>;
723
+ }
724
+
725
+ /**
726
+ * 向 Runtime 浏览器工具提供 Browser Run Quick Action 调用。
727
+ *
728
+ * @remarks
729
+ * Platform Plugin 在 Browser 绑定存在时生成快捷操作工具,工具在读取、提取或抓取页面时调用。
730
+ *
731
+ * 该 Port 保留 Browser Run 的通用 `action + options` 协议,具体工具仍由 `agents/browser` 辅助函数组装。
732
+ */
733
+ export interface RuntimeBrowserPort {
734
+ /**
735
+ * 执行一个 Browser Run Quick Action 并返回原始响应。
736
+ *
737
+ * @remarks
738
+ * `agents/browser` 的快捷操作辅助函数在对应 Pi 工具执行期调用。
739
+ *
740
+ * Runtime 不复制 Browser Run 的选项联合类型,避免两份协议随上游漂移。
741
+ */
742
+ quickAction(
743
+ action: string,
744
+ options: unknown,
745
+ ): Promise<Response>;
746
+ }
747
+
748
+ // #endregion
749
+
750
+ // #region 模型与 Cloudflare 平台端口
751
+
752
+ /**
753
+ * 列出 Runtime 可选的模型调用协议。
754
+ *
755
+ * @remarks
756
+ * Provider Plugin 在组装模型端点时设置,Pi Adapter 在注册模型时读取。
757
+ *
758
+ * 这是 Runtime 与 Pi Adapter 的稳定协议,新值必须先有对应的 Adapter 实现。
759
+ */
760
+ export type RuntimeModelProtocol =
761
+ | "openai-chat"
762
+ | "anthropic-messages"
763
+ | "google-generative-ai"
764
+ | "openai-codex-responses";
765
+
766
+ /**
767
+ * 描述一个已解析凭据的模型 API 端点。
768
+ *
769
+ * @remarks
770
+ * Provider Plugin 在装配时构造,Pi Adapter 启用时依次注册其中的模型。
771
+ *
772
+ * 凭据只留在 Port 对象,不进入 `RuntimeProfile` 或持久状态;术语见 `../index.ts`。
773
+ */
774
+ export interface RuntimeModelEndpoint {
775
+ protocol: RuntimeModelProtocol;
776
+ /** Resolved credential; never enters RuntimeProfile or persisted state. */
777
+ apiKey: string;
778
+ /** Resolved request headers; never enter RuntimeProfile or persisted state. */
779
+ headers?: Readonly<Record<string, string>>;
780
+ baseURL: string;
781
+ models: readonly string[];
782
+ }
783
+
784
+ /**
785
+ * 向 Runtime 提供本次装配可用的模型端点。
786
+ *
787
+ * @remarks
788
+ * Provider Plugin 贡献它,Builder 在提交前校验,Pi Adapter 在激活与每次解析模型时读取。
789
+ *
790
+ * Runtime 只依赖已解析结果,不知道环境变量或业务模型配置的来源。
791
+ */
792
+ export interface RuntimeProviderPort {
793
+ endpoints: readonly RuntimeModelEndpoint[];
794
+ /** First configured model; used by auxiliary consumers and legacy fallback. */
795
+ defaultModel: string;
796
+ }
797
+
798
+ /**
799
+ * 向 Runtime 提供 Cloudflare 执行平台上的可授权能力。
800
+ *
801
+ * @remarks
802
+ * Platform Plugin 贡献它,Workspace Codemode、Browser 工具、遥测和工具门卫按需使用。
803
+ *
804
+ * Worker Loader 与网络出口由 Host 选择,使 Dynamic Worker 只获得已授权绑定;术语见 `../index.ts`。
805
+ */
806
+ export interface RuntimePlatformPort {
807
+ /** Workspace Codemode 在创建 Dynamic Worker 执行器时使用的 Worker Loader。 */
808
+ loader: WorkerLoader;
809
+ /** Platform Plugin 存在 Browser Run 绑定时用它生成浏览器工具。 */
810
+ browser?: RuntimeBrowserPort;
811
+ /**
812
+ * 为一次 Dynamic Worker 组装取得已限定的网络出口。
813
+ *
814
+ * @remarks
815
+ * Workspace Plugin 创建 Codemode 工具时调用,并把返回的 `Fetcher` 交给 `DynamicWorkerExecutor`。
816
+ *
817
+ * 出口由 Host 通过 Service Binding 等平台边界控制,不使用无约束的 Runtime 全局网络能力。
818
+ */
819
+ outbound: () => Fetcher;
820
+ telemetryConsole?: boolean;
821
+ /**
822
+ * 在 Pi 工具真正执行前请 Host 审查本次调用。
823
+ *
824
+ * @remarks
825
+ * Pi 执行器包装每个工具候选时调用,Host 可根据名称、输入、执行档位与取消信号拒绝。
826
+ *
827
+ * 门卫留在 Host,因为它依赖本次调用的应用策略,不能被静态工具可见性取代。
828
+ */
829
+ gateTool?(request: {
830
+ toolCallId: string;
831
+ toolName: string;
832
+ input: unknown;
833
+ requiredExecutionLevel: ExecutionLevel;
834
+ signal: AbortSignal;
835
+ }): Promise<void>;
836
+ }
837
+
838
+ /**
839
+ * 汇总本次装配已授权的 Skill 来源。
840
+ *
841
+ * @remarks
842
+ * Builder 在生成候选 Snapshot 时创建,Pi 组装在生成 Skill 工具时读取。
843
+ *
844
+ * catalog、来源与脚本策略一起保留,避免装配期访问来源或让授权在 Skill 之间漂移。
845
+ */
846
+ export interface RuntimeSkillBindings {
847
+ /** Already-authorized external sources and their isolated script policy. */
848
+ sources: readonly RuntimeSkillSourceBinding[];
849
+ }
850
+
851
+ /**
852
+ * 限定一个 Skill 脚本可使用的网络、Workspace 和工具。
853
+ *
854
+ * @remarks
855
+ * Skill Plugin 在贡献来源时设置,Pi Skill 工具在决定是否注入脚本执行能力时读取。
856
+ *
857
+ * 这是已授权结果,执行期不应为某个 Skill 自动放宽。
858
+ */
859
+ export interface RuntimeSkillScriptPolicy {
860
+ network: "none" | "full";
861
+ workspace: "none" | "read" | "read-write";
862
+ tools: readonly string[];
863
+ }
864
+
865
+ /**
866
+ * 把一个已授权 Skill 来源与其脚本策略绑定。
867
+ *
868
+ * @remarks
869
+ * Builder 为每个 Skill 贡献创建,Pi 组装和 Skill 工具按名称查找并读取。
870
+ *
871
+ * 名称、内容来源与权限不分开存放,防止脚本改用其他 Skill 的授权。
872
+ */
873
+ export interface RuntimeSkillSourceBinding {
874
+ name: string;
875
+ /** Persisted catalog text used without loading the remote Skill source. */
876
+ description: string;
877
+ source: SkillSource;
878
+ script: RuntimeSkillScriptPolicy;
879
+ }
880
+
881
+ /**
882
+ * 汇总当前 Runtime Snapshot 已选中的外部依赖。
883
+ *
884
+ * @remarks
885
+ * Builder 在候选装配通过校验后创建,Runtime 和 Pi Adapter 在 Snapshot 生效期间读取。
886
+ *
887
+ * 它不携带业务 ID、Repository、数据库 Key、任意能力注册表或凭据配置;术语见 `../index.ts`。
888
+ */
889
+ export interface RuntimeBindings {
890
+ provider: RuntimeProviderPort;
891
+ platform: RuntimePlatformPort;
892
+ workspace?: WorkspacePort;
893
+ memory?: RuntimeMemoryPort;
894
+ skills: RuntimeSkillBindings;
895
+ turnEvents?: RuntimeTurnEventsPort;
896
+ }
897
+
898
+ // #endregion