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

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 (125) hide show
  1. package/package.json +11 -9
  2. package/src/adapter/cloudflare/agent.ts +177 -122
  3. package/src/adapter/cloudflare/define-agent.ts +47 -26
  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 +15 -0
  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/agent-context.ts +1 -1
  15. package/src/config/assembler.ts +48 -31
  16. package/src/config/assembly-snapshot.ts +1 -1
  17. package/src/config/definition.ts +1 -1
  18. package/src/config/harness-runtime.ts +51 -13
  19. package/src/config/model-guidance.ts +20 -0
  20. package/src/config/pinning.ts +39 -5
  21. package/src/config/ports.ts +57 -7
  22. package/src/config/public-contracts.ts +2 -2
  23. package/src/context/assembly.ts +1 -1
  24. package/src/context/extension/assembly.ts +2 -2
  25. package/src/context/memory/budget/gate.ts +19 -3
  26. package/src/conversation/harness-resume.ts +89 -238
  27. package/src/conversation/harness-stream.ts +87 -71
  28. package/src/conversation/history.ts +154 -152
  29. package/src/conversation/message/contract.ts +12 -0
  30. package/src/conversation/message/conversion.ts +3 -3
  31. package/src/conversation/message/projection.ts +61 -21
  32. package/src/conversation/session-entry.ts +29 -0
  33. package/src/conversation/state.ts +23 -2
  34. package/src/harness/governance.ts +206 -0
  35. package/src/harness/index.ts +3 -0
  36. package/src/harness/session-harness.ts +255 -446
  37. package/src/harness/submission-operation.ts +15 -40
  38. package/src/index.ts +18 -8
  39. package/src/lib/artifacts.ts +18 -0
  40. package/src/lib/execution-level.ts +13 -0
  41. package/src/lib/prompt.ts +9 -10
  42. package/src/lib/token-estimate.ts +8 -0
  43. package/src/model-protocol/openrouter.ts +41 -0
  44. package/src/models/index.ts +200 -35
  45. package/src/models/openrouter/messages.ts +13 -8
  46. package/src/models/openrouter/openai.ts +200 -0
  47. package/src/models/openrouter/protocol-response.ts +85 -0
  48. package/src/models/provider-streams.ts +45 -0
  49. package/src/session/cloudflare/migration.ts +382 -864
  50. package/src/session/cloudflare/storage.ts +13 -536
  51. package/src/session/index.ts +22 -35
  52. package/src/skills/springbrand-worker-website/index.ts +1 -1
  53. package/src/submission/admission.ts +12 -1
  54. package/src/submission/contracts.ts +42 -2
  55. package/src/submission/delivery.ts +1 -1
  56. package/src/submission/finalization.ts +36 -15
  57. package/src/submission/repository.ts +64 -25
  58. package/src/submission/steer-delivery.ts +32 -76
  59. package/src/submission/unattended.ts +40 -0
  60. package/src/telemetry/coordinator.ts +1 -1
  61. package/src/telemetry/subagent-lifecycle.ts +1 -1
  62. package/src/telemetry/turn-events.ts +35 -25
  63. package/src/tools/README.md +44 -0
  64. package/src/tools/{ai-adapter.ts → adapters/ai-to-pi.ts} +6 -9
  65. package/src/tools/{declared.ts → adapters/declared.ts} +6 -2
  66. package/src/tools/{nested-tools.ts → adapters/pi-to-ai.ts} +4 -4
  67. package/src/tools/assistant/ask-user.ts +317 -0
  68. package/src/tools/assistant/candidate.ts +15 -0
  69. package/src/tools/assistant/followups.ts +34 -0
  70. package/src/tools/assistant/index.ts +19 -0
  71. package/src/tools/assistant/memory.ts +73 -0
  72. package/src/tools/assistant/plan.ts +98 -0
  73. package/src/tools/{time.ts → assistant/time.ts} +1 -1
  74. package/src/tools/{core-host.ts → codemode/adapter.ts} +50 -53
  75. package/src/tools/{core.ts → codemode/index.ts} +36 -92
  76. package/src/tools/codemode/workspace-connector.ts +198 -0
  77. package/src/tools/extension/index.ts +42 -0
  78. package/src/tools/index.ts +29 -26
  79. package/src/tools/{gateway.ts → mcp/gateway.ts} +19 -19
  80. package/src/tools/{mcp.ts → mcp/index.ts} +5 -5
  81. package/src/tools/runtime/activation.ts +40 -0
  82. package/src/tools/{approval → runtime/approval}/repository.ts +13 -12
  83. package/src/tools/runtime/compiler.ts +246 -0
  84. package/src/tools/runtime/contracts.ts +140 -0
  85. package/src/tools/{decision-gate.ts → runtime/decision-gate.ts} +149 -39
  86. package/src/tools/{human-decisions.ts → runtime/human-decisions.ts} +4 -4
  87. package/src/tools/{interaction → runtime/interaction}/repository.ts +1 -7
  88. package/src/tools/runtime/result.ts +22 -0
  89. package/src/tools/runtime/unattended-error.ts +4 -0
  90. package/src/tools/sandbox/index.ts +228 -0
  91. package/src/tools/schedule/index.ts +301 -0
  92. package/src/tools/skill/contracts.ts +20 -0
  93. package/src/tools/skill/index.ts +99 -0
  94. package/src/tools/skill/resources.ts +322 -0
  95. package/src/tools/skill/scripts.ts +168 -0
  96. package/src/tools/{subagent-authority.ts → subagent/authority.ts} +31 -31
  97. package/src/tools/{subagent.ts → subagent/index.ts} +34 -37
  98. package/src/tools/{subagent-run-repository.ts → subagent/repository.ts} +1 -1
  99. package/src/tools/{subagent-runtime.ts → subagent/runtime.ts} +1 -1
  100. package/src/tools/{temporary-agent → subagent/temporary}/approvals.ts +4 -7
  101. package/src/tools/{temporary-agent → subagent/temporary}/core.ts +2 -3
  102. package/src/tools/{temporary-agent → subagent/temporary}/runner.ts +1 -1
  103. package/src/tools/{temporary-agent → subagent/temporary}/workspace.ts +1 -4
  104. package/src/tools/{web-fetch.ts → web/fetch.ts} +4 -13
  105. package/src/tools/web/index.ts +2 -0
  106. package/src/tools/web/search/api.ts +1322 -0
  107. package/src/tools/web/search/index.ts +2 -0
  108. package/src/tools/{web-search/web-search.ts → web/search/search.ts} +5 -7
  109. package/src/tools/{workspace-sandbox.ts → workspace/index.ts} +12 -272
  110. package/src/tools/{workspace-revision.ts → workspace/revision.ts} +3 -3
  111. package/src/tools/base.ts +0 -534
  112. package/src/tools/compiler.ts +0 -327
  113. package/src/tools/schedule.ts +0 -261
  114. package/src/tools/skill.ts +0 -565
  115. package/src/tools/web-search/api.ts +0 -1318
  116. package/src/tools/web-search/index.ts +0 -2
  117. package/src/tools/workspace-state-connector.ts +0 -146
  118. package/src/tools/{approval → runtime/approval}/index.ts +0 -0
  119. package/src/tools/{interaction → runtime/interaction}/index.ts +0 -0
  120. package/src/tools/{temporary-agent → subagent/temporary}/coordinator.ts +0 -0
  121. package/src/tools/{subagent-types → subagent/types}/contract.ts +0 -0
  122. package/src/tools/{subagent-types → subagent/types}/extract/index.ts +0 -0
  123. package/src/tools/{subagent-types → subagent/types}/fanout/index.ts +0 -0
  124. package/src/tools/{subagent-types → subagent/types}/registry.ts +1 -1
  125. /package/src/tools/{workspace-versioning.ts → workspace/versioning.ts} +0 -0
@@ -157,6 +157,11 @@ export interface PreparedPiRuntime {
157
157
  export interface PinPiRuntimeOptions {
158
158
  readonly prepared: PreparedPiRuntime;
159
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;
160
165
  /**
161
166
  * 读取一个扩展要写入固定系统提示词的上下文。
162
167
  *
@@ -249,9 +254,20 @@ function describeTools(candidates: readonly PiToolCandidate[]) {
249
254
  description: candidate.tool.description ?? candidate.tool.label,
250
255
  parameters: candidate.tool.parameters,
251
256
  requiredExecutionLevel: candidate.requiredExecutionLevel,
257
+ ...(candidate.confirmation ? { confirmation: true } : {}),
252
258
  ...(candidate.alwaysRequiresApproval
253
259
  ? { alwaysRequiresApproval: true }
254
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
+ : {}),
255
271
  ...(candidate.deferLoading ? { deferLoading: true } : {}),
256
272
  ...(candidate.source ? { source: candidate.source } : {}),
257
273
  retry: piToolRetryPolicy(candidate),
@@ -267,10 +283,25 @@ function describeRuntime(
267
283
  candidates: readonly PiToolCandidate[],
268
284
  loadedExtensions: readonly PiLoadedExtension[],
269
285
  ): string {
286
+ const model = snapshot.pi.model;
287
+ const openRouterRouting = model.compat && "openRouterRouting" in model.compat
288
+ ? model.compat.openRouterRouting
289
+ : undefined;
270
290
  return JSON.stringify({
271
291
  version: 1,
272
- model: snapshot.pi.model.id,
273
- provider: snapshot.pi.model.provider,
292
+ model: model.id,
293
+ provider: model.provider,
294
+ modelConfig: {
295
+ api: model.api,
296
+ name: model.name,
297
+ reasoning: model.reasoning,
298
+ input: model.input,
299
+ contextWindow: model.contextWindow,
300
+ maxTokens: model.maxTokens,
301
+ cost: model.cost,
302
+ ...(model.thinkingLevelMap ? { thinkingLevelMap: model.thinkingLevelMap } : {}),
303
+ ...(openRouterRouting ? { openRouterRouting } : {}),
304
+ },
274
305
  thinking: snapshot.pi.thinkingLevel,
275
306
  systemPrompt: snapshot.pi.systemPrompt,
276
307
  executionLevel: snapshot.profile.executionLevel,
@@ -481,11 +512,14 @@ export async function pinPiRuntime(
481
512
  ): Promise<PinnedPiRuntime> {
482
513
  const state = readPreparedPiRuntime(options.prepared, owner);
483
514
  const { snapshot, assembly } = state;
515
+ const includeMemory = options.includeMemory !== false;
484
516
  const context = await assemblePiSystemContext({
485
517
  baseSystemPrompt: snapshot.pi.systemPrompt,
486
- memory: snapshot.profile.memory,
487
- memoryPort: snapshot.bindings.memory,
488
- workspace: snapshot.bindings.workspace,
518
+ memory: includeMemory
519
+ ? snapshot.profile.memory
520
+ : { ...snapshot.profile.memory, enabled: false },
521
+ memoryPort: includeMemory ? snapshot.bindings.memory : undefined,
522
+ workspace: includeMemory ? snapshot.bindings.workspace : undefined,
489
523
  skills: snapshot.bindings.skills.sources,
490
524
  extensionContexts: assembly.context,
491
525
  readExtensionContext: options.readExtensionContext,
@@ -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
  /**
@@ -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,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 会返回