@springbrand/agent-runtime 0.2.0-alpha.72 → 0.3.0-alpha.2

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 (141) hide show
  1. package/package.json +3 -3
  2. package/src/{agent-tool-runtime.ts → adapter/cloudflare/agent-tool.ts} +1 -1
  3. package/src/adapter/cloudflare/agent.ts +1592 -0
  4. package/src/{db/index.ts → adapter/cloudflare/database.ts} +18 -55
  5. package/src/{runtime-agent.ts → adapter/cloudflare/define-agent.ts} +25 -35
  6. package/src/adapter/cloudflare/dynamic-worker-observability.ts +1 -1
  7. package/src/adapter/cloudflare/resources/runtime-resources.ts +4 -4
  8. package/src/adapter/cloudflare/sandbox/adapter.ts +1 -1
  9. package/src/{db → adapter/cloudflare}/schema.ts +16 -83
  10. package/src/adapter/cloudflare/subagent/definition.ts +63 -33
  11. package/src/adapter/cloudflare/subagent/runner.ts +174 -120
  12. package/src/adapter/cloudflare/subagent/tools.ts +13 -14
  13. package/src/adapter/cloudflare/universal-agent/preparation.ts +7 -7
  14. package/src/adapter/cloudflare/universal-agent/tools.ts +10 -10
  15. package/src/adapter/cloudflare/workspace/git-fs.ts +1 -1
  16. package/src/adapter/cloudflare/workspace/scoped-workspace.ts +1 -1
  17. package/src/adapter/cloudflare/workspace/version-control.ts +2 -2
  18. package/src/config/activation.ts +140 -0
  19. package/src/{runtime-agent-context.ts → config/agent-context.ts} +3 -3
  20. package/src/{runtime-assembler.ts → config/assembler.ts} +20 -19
  21. package/src/{kernel/runtime-assembly.ts → config/assembly-projection.ts} +4 -4
  22. package/src/{pi/assembly/snapshot.ts → config/assembly-snapshot.ts} +6 -6
  23. package/src/{runtime-definition.ts → config/definition.ts} +13 -13
  24. package/src/config/harness-runtime.ts +182 -0
  25. package/src/config/index.ts +14 -0
  26. package/src/{pi/runtime-adapter/assembly.ts → config/pinning.ts} +38 -16
  27. package/src/{kernel/bindings.ts → config/ports.ts} +9 -13
  28. package/src/{kernel → config}/profile.ts +7 -0
  29. package/src/{kernel → config}/public-contracts.ts +6 -6
  30. package/src/{kernel → config}/runtime-load.ts +1 -1
  31. package/src/{pi/assembly/context.ts → context/assembly.ts} +4 -206
  32. package/src/{pi/assembly/extensions.ts → context/extension/assembly.ts} +5 -5
  33. package/src/context/extension/index.ts +3 -0
  34. package/src/context/index.ts +6 -0
  35. package/src/{layers/context → context/memory}/budget/gate.ts +2 -2
  36. package/src/conversation/harness-resume.ts +288 -0
  37. package/src/conversation/harness-stream.ts +98 -0
  38. package/src/{pi/runtime-adapter/transcript.ts → conversation/history.ts} +206 -233
  39. package/src/conversation/index.ts +6 -0
  40. package/src/{pi → conversation}/message/contract.ts +3 -0
  41. package/src/{pi → conversation}/message/conversion.ts +75 -0
  42. package/src/{pi → conversation}/message/index.ts +1 -0
  43. package/src/{pi → conversation}/message/model-input.ts +1 -1
  44. package/src/{pi → conversation}/message/projection.ts +76 -10
  45. package/src/{db/message-ui.repo.ts → conversation/repository.ts} +4 -0
  46. package/src/conversation/state.ts +175 -0
  47. package/src/harness/index.ts +7 -0
  48. package/src/harness/session-harness.ts +481 -0
  49. package/src/harness/submission-operation.ts +49 -0
  50. package/src/index.ts +38 -43
  51. package/src/lib/mcp.ts +1 -1
  52. package/src/{pi/runtime-adapter/models.ts → models/index.ts} +64 -18
  53. package/src/{pi/turn/tool-recovery.ts → session/cloudflare/legacy-tool-recovery.ts} +33 -525
  54. package/src/{pi/session → session/cloudflare}/migration.ts +334 -8
  55. package/src/{pi/session → session/cloudflare}/storage.ts +8 -36
  56. package/src/session/index.ts +39 -0
  57. package/src/submission/admission.ts +275 -0
  58. package/src/{kernel/receipts.ts → submission/contracts.ts} +14 -0
  59. package/src/submission/delivery.ts +212 -0
  60. package/src/submission/finalization.ts +111 -0
  61. package/src/submission/index.ts +9 -0
  62. package/src/{kernel/submission-lifecycle.ts → submission/lifecycle.ts} +41 -28
  63. package/src/{db/submission.repo.ts → submission/repository.ts} +62 -119
  64. package/src/submission/steer-delivery.ts +167 -0
  65. package/src/{db/steer.repo.ts → submission/steer-repository.ts} +27 -5
  66. package/src/telemetry/contract.ts +12 -0
  67. package/src/telemetry/coordinator.ts +65 -0
  68. package/src/telemetry/delivery.ts +2 -2
  69. package/src/telemetry/index.ts +5 -0
  70. package/src/{model-usage.ts → telemetry/model-usage.ts} +1 -1
  71. package/src/telemetry/recorder.ts +1 -1
  72. package/src/telemetry/runtime-telemetry.ts +12 -0
  73. package/src/{kernel/durable-lifecycle.ts → telemetry/subagent-lifecycle.ts} +1 -1
  74. package/src/telemetry/turn-events.ts +279 -0
  75. package/src/{pi/tool → tools}/ai-adapter.ts +2 -2
  76. package/src/tools/approval/index.ts +1 -0
  77. package/src/{db/approval.repo.ts → tools/approval/repository.ts} +10 -30
  78. package/src/{pi/tool → tools}/base.ts +14 -30
  79. package/src/tools/compiler.ts +327 -0
  80. package/src/{pi/tool → tools}/core-host.ts +3 -3
  81. package/src/{pi/tool → tools}/core.ts +3 -3
  82. package/src/tools/decision-gate.ts +227 -0
  83. package/src/{pi/tool → tools}/gateway.ts +1 -1
  84. package/src/tools/human-decisions.ts +127 -0
  85. package/src/tools/index.ts +30 -0
  86. package/src/tools/interaction/index.ts +1 -0
  87. package/src/{pi/tool → tools}/mcp.ts +1 -1
  88. package/src/{pi/tool → tools}/schedule.ts +3 -3
  89. package/src/{pi/tool → tools}/skill.ts +4 -4
  90. package/src/{kernel → tools}/subagent-runtime.ts +1 -1
  91. package/src/{pi/tool → tools}/subagent.ts +4 -4
  92. package/src/tools/temporary-agent/approvals.ts +126 -0
  93. package/src/{layers/orchestration/temporary-agent/core.ts → tools/temporary-agent/coordinator.ts} +41 -49
  94. package/src/tools/temporary-agent/core.ts +53 -0
  95. package/src/{layers/orchestration → tools}/temporary-agent/runner.ts +1 -1
  96. package/src/{layers/orchestration → tools}/temporary-agent/workspace.ts +1 -1
  97. package/src/{pi/tool → tools}/web-search/api.ts +1 -1
  98. package/src/{pi/tool → tools}/workspace-revision.ts +2 -2
  99. package/src/{pi/tool → tools}/workspace-sandbox.ts +2 -2
  100. package/src/{pi/tool → tools}/workspace-state-connector.ts +1 -1
  101. package/src/db/milestone.repo.ts +0 -104
  102. package/src/db/settlement.repo.ts +0 -104
  103. package/src/kernel/approval-lifecycle.ts +0 -638
  104. package/src/kernel/interaction-lifecycle.ts +0 -433
  105. package/src/kernel/recoverable-chat-agent.ts +0 -1020
  106. package/src/kernel/state.ts +0 -91
  107. package/src/pi/assembly/index.ts +0 -19
  108. package/src/pi/runtime-adapter/execution.ts +0 -1163
  109. package/src/pi/runtime-adapter/index.ts +0 -293
  110. package/src/pi/runtime-adapter/recovery.ts +0 -982
  111. package/src/pi/session/index.ts +0 -24
  112. package/src/pi/tool/compiler.ts +0 -483
  113. package/src/pi/tool/index.ts +0 -38
  114. package/src/pi/turn/approval.ts +0 -181
  115. package/src/pi/turn/index.ts +0 -82
  116. package/src/pi/turn/interaction.ts +0 -181
  117. package/src/runtime.ts +0 -4760
  118. /package/src/{kernel/runtime-assembly-view.ts → config/assembly-view.ts} +0 -0
  119. /package/src/{kernel → config}/degradation.ts +0 -0
  120. /package/src/{kernel → config}/runtime-config.ts +0 -0
  121. /package/src/{kernel/extensions.ts → context/extension/contracts.ts} +0 -0
  122. /package/src/{db/ext-context.repo.ts → context/extension/repository.ts} +0 -0
  123. /package/src/{pi/runtime-adapter/openrouter-messages.ts → models/openrouter/messages.ts} +0 -0
  124. /package/src/{pi/runtime-adapter → models/openrouter}/test-fixtures/openrouter-tool-search.sse +0 -0
  125. /package/src/{db/submission-admission.repo.ts → submission/admission-repository.ts} +0 -0
  126. /package/src/{db/telemetry-outbox.repo.ts → telemetry/repository.ts} +0 -0
  127. /package/src/{db/runtime-event-outbox.repo.ts → telemetry/runtime-event-repository.ts} +0 -0
  128. /package/src/{pi/tool → tools}/declared.ts +0 -0
  129. /package/src/{db/interaction.repo.ts → tools/interaction/repository.ts} +0 -0
  130. /package/src/{pi/tool → tools}/nested-tools.ts +0 -0
  131. /package/src/{kernel/submission-authority.ts → tools/subagent-authority.ts} +0 -0
  132. /package/src/{db/agent-tool.repo.ts → tools/subagent-run-repository.ts} +0 -0
  133. /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/contract.ts +0 -0
  134. /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/extract/index.ts +0 -0
  135. /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/fanout/index.ts +0 -0
  136. /package/src/{layers/orchestration/subagents/agent-types → tools/subagent-types}/registry.ts +0 -0
  137. /package/src/{pi/tool → tools}/time.ts +0 -0
  138. /package/src/{pi/tool → tools}/web-fetch.ts +0 -0
  139. /package/src/{pi/tool → tools}/web-search/index.ts +0 -0
  140. /package/src/{pi/tool → tools}/web-search/web-search.ts +0 -0
  141. /package/src/{workspace-versioning.ts → tools/workspace-versioning.ts} +0 -0
package/src/lib/mcp.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { RetryOptions } from "agents";
2
- import { withRuntimeLoadTimeout } from "../kernel/runtime-load";
2
+ import { withRuntimeLoadTimeout } from "../config/runtime-load";
3
3
 
4
4
  const MCP_RETRY: RetryOptions = {
5
5
  maxAttempts: 3,
@@ -48,9 +48,9 @@ import type {
48
48
  RuntimeModelInputModality,
49
49
  RuntimeModelProtocol,
50
50
  RuntimeProviderPort,
51
- } from "../../kernel/bindings";
52
- import { modelInputMessages } from "../message/model-input";
53
- import { openRouterMessagesApi } from "./openrouter-messages";
51
+ } from "../config/ports";
52
+ import { modelInputMessages } from "../conversation/message/model-input";
53
+ import { openRouterMessagesApi } from "./openrouter/messages";
54
54
 
55
55
  const CATALOGS = {
56
56
  "openai-chat": openaiProvider().getModels(),
@@ -60,8 +60,6 @@ const CATALOGS = {
60
60
  "openai-codex-responses": openaiCodexProvider().getModels(),
61
61
  } satisfies Record<RuntimeModelProtocol, readonly Model<Api>[]>;
62
62
 
63
- const PROVIDER_MAX_RETRIES = 2;
64
-
65
63
  const MESSAGES_HOSTED_INPUT_MODALITIES = ["image", "file"] as const;
66
64
  const NO_HOSTED_INPUT_MODALITIES: readonly RuntimeModelInputModality[] = [];
67
65
 
@@ -83,7 +81,7 @@ function adapterHostedInputModalities(
83
81
  // 结构上不可能收敛**,表现为前端 think 转到恢复预算耗尽为止。
84
82
  //
85
83
  // 调到 240s:比实测静默期留约 7 倍余量。代价是连接真死时单次要等更久,
86
- // 所以 runtime.ts 同时把 stall 的恢复次数单独收窄(见 CHAT_STALL_MAX_ATTEMPTS)。
84
+ // Harness owns bounded provider retries; this timeout only detects a stream that stopped making progress.
87
85
  export const MODEL_STREAM_STALL_TIMEOUT_MS = 240_000;
88
86
  export const MODEL_STREAM_STALL_MESSAGE =
89
87
  `Chat stream stalled: no activity for ${MODEL_STREAM_STALL_TIMEOUT_MS}ms; the turn was aborted by the stall watchdog.`;
@@ -113,6 +111,12 @@ export type PiGenerationLifecycleEvent =
113
111
  readonly generationId: string;
114
112
  readonly timestamp: number;
115
113
  readonly durationMs: number;
114
+ readonly responseHeadersMs?: number;
115
+ readonly firstRawEventMs?: number;
116
+ readonly firstMeaningfulEventMs?: number;
117
+ readonly firstTextEventMs?: number;
118
+ readonly sourceWaitMs?: number;
119
+ readonly forwardingOverheadMs?: number;
116
120
  readonly outcome: "success" | "error" | "cancelled";
117
121
  readonly stopReason?: string;
118
122
  readonly errorName?: string;
@@ -302,8 +306,12 @@ async function* stopStalledModelStream(
302
306
  let stalled = false;
303
307
  let stallError: ChatStreamStalledError | undefined;
304
308
  let idleWaitMs = 0;
309
+ let sourceWaitMs = 0;
310
+ let forwardingOverheadMs = 0;
311
+ let yieldedAt: number | undefined;
305
312
  let rawEventCount = 0;
306
313
  let meaningfulEventCount = 0;
314
+ let firstTextSeen = false;
307
315
  let lastRawEventAt: number | undefined;
308
316
  let lastRawEventType: AssistantMessageEvent["type"] | undefined;
309
317
  const streamedContent = new Set<string>();
@@ -344,6 +352,10 @@ async function* stopStalledModelStream(
344
352
  });
345
353
  try {
346
354
  while (true) {
355
+ if (yieldedAt !== undefined) {
356
+ forwardingOverheadMs += Math.max(0, Date.now() - yieldedAt);
357
+ yieldedAt = undefined;
358
+ }
347
359
  const waitStartedAt = Date.now();
348
360
  const nextPromise = iterator
349
361
  ? iterator.next()
@@ -375,6 +387,7 @@ async function* stopStalledModelStream(
375
387
  timer = undefined;
376
388
  }
377
389
  if (stalled) throw stallError;
390
+ sourceWaitMs += Math.max(0, Date.now() - waitStartedAt);
378
391
  if (next.done) break;
379
392
  const event = next.value;
380
393
  rawEventCount += 1;
@@ -395,6 +408,8 @@ async function* stopStalledModelStream(
395
408
  output: event.type === "done" ? event.message : event.error,
396
409
  rawEventCount,
397
410
  meaningfulEventCount,
411
+ sourceWaitMs,
412
+ forwardingOverheadMs,
398
413
  });
399
414
  yield event;
400
415
  return;
@@ -410,6 +425,15 @@ async function* stopStalledModelStream(
410
425
  lastMeaningfulActivityType = progress;
411
426
  idleWaitMs = 0;
412
427
  }
428
+ if (
429
+ !firstTextSeen &&
430
+ (event.type === "text_delta" || event.type === "text_end") &&
431
+ (event.type === "text_delta" ? event.delta : event.content).trim()
432
+ ) {
433
+ firstTextSeen = true;
434
+ probe("first_text_event", { eventType: event.type });
435
+ }
436
+ yieldedAt = Date.now();
413
437
  yield event;
414
438
  }
415
439
  } finally {
@@ -431,7 +455,7 @@ function trimTrailingSlash(value: string): string {
431
455
  /**
432
456
  * 算出一个已解析模型真正会被请求的 URL。
433
457
  *
434
- * {@link withProviderRetry} 在每次派发模型请求前调用它写观测日志;诊断"这个 Agent 到底调了哪个 LLM"时也可以直接复用。
458
+ * {@link withProviderBoundary} 在每次派发模型请求前调用它写观测日志;诊断"这个 Agent 到底调了哪个 LLM"时也可以直接复用。
435
459
  *
436
460
  * 各协议的路径由底层 SDK 决定,这里必须与之逐条对齐:OpenAI 兼容 SDK 用 `baseURL + /chat/completions`,
437
461
  * Anthropic SDK 用 `baseURL + /v1/messages`(纯字符串拼接,不会去重 `/v1`),Google 的 baseUrl 已含版本段,
@@ -458,18 +482,15 @@ export function modelRequestUrl(model: Model<Api>): string {
458
482
  /**
459
483
  * 给模型请求补上可中断的空闲终止边界。
460
484
  *
461
- * Runtime Turn 和 SubAgent 在把 `Models.streamSimple` 交给 Pi 前调用;显式传入的重试次数优先。
462
- *
463
- * 调用方可以覆盖默认的 2 次 Provider 重试;主 Turn 传 0,由 Submission
464
- * 统一持有恢复预算。连续 {@link MODEL_STREAM_STALL_TIMEOUT_MS} 毫秒没有可展示进展时中止 provider。
485
+ * Runtime Turn 和 SubAgent 在把 `Models.streamSimple` 交给 Harness 前调用。
486
+ * 本边界只负责载荷转换、观测和空闲超时;重试次数由 Harness 传入,这里不提供第二个默认值。
465
487
  *
466
488
  * 可选 observer 接收配对的 generation started/finished 事实及实际模型输入输出;响应头仅保留
467
489
  * 白名单 request id,永不携带 key 或任意响应 header。正文由 telemetry 隐私模式统一脱敏。
468
490
  * observer 的异常被隔离,不能改变模型执行结果。
469
491
  */
470
- export function withProviderRetry(
492
+ export function withProviderBoundary(
471
493
  streamFn: StreamFn,
472
- defaultMaxRetries = PROVIDER_MAX_RETRIES,
473
494
  defaultSessionId?: string,
474
495
  onGeneration?: PiGenerationLifecycleObserver,
475
496
  ): StreamFn {
@@ -503,6 +524,12 @@ export function withProviderRetry(
503
524
  let responseCount = 0;
504
525
  let upstreamRequestId: string | undefined;
505
526
  let responseStatus: number | undefined;
527
+ let responseHeadersMs: number | undefined;
528
+ let firstRawEventMs: number | undefined;
529
+ let firstMeaningfulEventMs: number | undefined;
530
+ let firstTextEventMs: number | undefined;
531
+ let sourceWaitMs: number | undefined;
532
+ let forwardingOverheadMs: number | undefined;
506
533
  let finished = false;
507
534
  const finish = (
508
535
  outcome: "success" | "error" | "cancelled",
@@ -515,11 +542,18 @@ export function withProviderRetry(
515
542
  ) => {
516
543
  if (finished) return;
517
544
  finished = true;
545
+ const finishedAt = Date.now();
518
546
  notify({
519
547
  type: "finished",
520
548
  generationId: requestId,
521
- timestamp: Date.now(),
522
- durationMs: Math.max(0, Date.now() - startedAt),
549
+ timestamp: finishedAt,
550
+ durationMs: Math.max(0, finishedAt - startedAt),
551
+ responseHeadersMs,
552
+ firstRawEventMs,
553
+ firstMeaningfulEventMs,
554
+ firstTextEventMs,
555
+ sourceWaitMs,
556
+ forwardingOverheadMs,
523
557
  outcome,
524
558
  ...details,
525
559
  ...(upstreamRequestId ? { upstreamRequestId } : {}),
@@ -527,7 +561,9 @@ export function withProviderRetry(
527
561
  });
528
562
  };
529
563
  const probe = (phase: string, details: Record<string, unknown> = {}) => {
564
+ const elapsedMs = Math.max(0, Date.now() - startedAt);
530
565
  if (phase === "response_headers") {
566
+ responseHeadersMs ??= elapsedMs;
531
567
  if (typeof details.upstreamRequestId === "string") {
532
568
  upstreamRequestId = details.upstreamRequestId;
533
569
  }
@@ -536,6 +572,17 @@ export function withProviderRetry(
536
572
  }
537
573
  return;
538
574
  }
575
+ if (phase === "first_raw_event") firstRawEventMs ??= elapsedMs;
576
+ if (phase === "first_meaningful_event") {
577
+ firstMeaningfulEventMs ??= elapsedMs;
578
+ }
579
+ if (phase === "first_text_event") firstTextEventMs ??= elapsedMs;
580
+ if (typeof details.sourceWaitMs === "number") {
581
+ sourceWaitMs = details.sourceWaitMs;
582
+ }
583
+ if (typeof details.forwardingOverheadMs === "number") {
584
+ forwardingOverheadMs = details.forwardingOverheadMs;
585
+ }
539
586
  if (phase === "done") {
540
587
  finish("success", {
541
588
  ...(typeof details.stopReason === "string"
@@ -579,7 +626,7 @@ export function withProviderRetry(
579
626
  signal: options?.signal
580
627
  ? AbortSignal.any([options.signal, watchdog.signal])
581
628
  : watchdog.signal,
582
- maxRetries: options?.maxRetries ?? defaultMaxRetries,
629
+ maxRetries: options?.maxRetries,
583
630
  sessionId,
584
631
  onPayload: async (payload, activeModel) =>
585
632
  pdfPayload(
@@ -743,7 +790,6 @@ function configuredModel(
743
790
  ? {
744
791
  compat: {
745
792
  ...anthropicMessagesCompat,
746
- // OpenRouter rejects Anthropic's mid-conversation effort messages and block binding.
747
793
  supportsMidConvoEffort: false,
748
794
  supportsEagerToolInputStreaming: false,
749
795
  supportsStrictTools:
@@ -789,7 +835,7 @@ export function resolvePiModel(
789
835
  /**
790
836
  * 用当前部署端点完整重建一个已有的 Pi 模型集合。
791
837
  *
792
- * PiRuntimeAdapter 激活新运行快照时调用它;需要复用 MutableModels 的调用方也可以调用,并继续使用返回的同一实例。
838
+ * HarnessRuntimeConfig 激活新运行快照时调用它;需要复用 MutableModels 的调用方也可以调用,并继续使用返回的同一实例。
793
839
  * 该函数在全部新 provider 校验通过后才清空并替换集合,所以失败时旧集合保持可用。
794
840
  *
795
841
  * Pi 当前用 provider.id 在 Map 中注册和路由请求,因此每个部署端点都必须同时注册唯一 provider、对应模型、认证解析器和协议实现。