@springbrand/agent-runtime 0.3.0-alpha.1 → 0.3.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/package.json +6 -6
  2. package/src/adapter/cloudflare/agent.ts +157 -14
  3. package/src/adapter/cloudflare/define-agent.ts +12 -7
  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 +4 -4
  9. package/src/adapter/cloudflare/subagent/runner.ts +1 -1
  10. package/src/adapter/cloudflare/subagent/tools.ts +2 -2
  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 +29 -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 +9 -1
  19. package/src/config/model-guidance.ts +21 -0
  20. package/src/config/pinning.ts +22 -3
  21. package/src/config/ports.ts +27 -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-stream.ts +2 -1
  27. package/src/conversation/message/projection.ts +38 -21
  28. package/src/conversation/state.ts +23 -2
  29. package/src/harness/session-harness.ts +86 -5
  30. package/src/index.ts +7 -7
  31. package/src/lib/artifacts.ts +18 -0
  32. package/src/lib/execution-level.ts +13 -0
  33. package/src/lib/prompt.ts +7 -6
  34. package/src/lib/token-estimate.ts +8 -0
  35. package/src/models/index.ts +1 -0
  36. package/src/session/cloudflare/migration.ts +70 -6
  37. package/src/skills/springbrand-worker-website/index.ts +1 -1
  38. package/src/submission/admission.ts +12 -1
  39. package/src/submission/contracts.ts +42 -2
  40. package/src/submission/delivery.ts +1 -1
  41. package/src/submission/finalization.ts +1 -1
  42. package/src/submission/repository.ts +64 -4
  43. package/src/submission/unattended.ts +40 -0
  44. package/src/telemetry/coordinator.ts +1 -1
  45. package/src/telemetry/subagent-lifecycle.ts +1 -1
  46. package/src/telemetry/turn-events.ts +1 -1
  47. package/src/tools/README.md +44 -0
  48. package/src/tools/{ai-adapter.ts → adapters/ai-to-pi.ts} +6 -9
  49. package/src/tools/{declared.ts → adapters/declared.ts} +6 -2
  50. package/src/tools/{nested-tools.ts → adapters/pi-to-ai.ts} +2 -2
  51. package/src/tools/assistant/ask-user.ts +317 -0
  52. package/src/tools/assistant/candidate.ts +15 -0
  53. package/src/tools/assistant/followups.ts +34 -0
  54. package/src/tools/assistant/index.ts +19 -0
  55. package/src/tools/assistant/memory.ts +73 -0
  56. package/src/tools/assistant/plan.ts +98 -0
  57. package/src/tools/{time.ts → assistant/time.ts} +1 -1
  58. package/src/tools/{core-host.ts → codemode/adapter.ts} +50 -49
  59. package/src/tools/{core.ts → codemode/index.ts} +36 -92
  60. package/src/tools/codemode/workspace-connector.ts +198 -0
  61. package/src/tools/extension/index.ts +42 -0
  62. package/src/tools/index.ts +28 -26
  63. package/src/tools/{gateway.ts → mcp/gateway.ts} +19 -19
  64. package/src/tools/{mcp.ts → mcp/index.ts} +5 -5
  65. package/src/tools/{approval → runtime/approval}/repository.ts +13 -12
  66. package/src/tools/{compiler.ts → runtime/compiler.ts} +84 -147
  67. package/src/tools/runtime/contracts.ts +117 -0
  68. package/src/tools/{decision-gate.ts → runtime/decision-gate.ts} +147 -37
  69. package/src/tools/{human-decisions.ts → runtime/human-decisions.ts} +4 -4
  70. package/src/tools/{interaction → runtime/interaction}/repository.ts +1 -7
  71. package/src/tools/runtime/result.ts +22 -0
  72. package/src/tools/runtime/unattended-error.ts +4 -0
  73. package/src/tools/sandbox/index.ts +228 -0
  74. package/src/tools/schedule/index.ts +301 -0
  75. package/src/tools/skill/contracts.ts +20 -0
  76. package/src/tools/skill/index.ts +99 -0
  77. package/src/tools/skill/resources.ts +322 -0
  78. package/src/tools/skill/scripts.ts +168 -0
  79. package/src/tools/{subagent-authority.ts → subagent/authority.ts} +31 -31
  80. package/src/tools/{subagent.ts → subagent/index.ts} +34 -37
  81. package/src/tools/{subagent-run-repository.ts → subagent/repository.ts} +1 -1
  82. package/src/tools/{subagent-runtime.ts → subagent/runtime.ts} +1 -1
  83. package/src/tools/{temporary-agent → subagent/temporary}/approvals.ts +4 -7
  84. package/src/tools/{temporary-agent → subagent/temporary}/core.ts +1 -1
  85. package/src/tools/{temporary-agent → subagent/temporary}/runner.ts +1 -1
  86. package/src/tools/{temporary-agent → subagent/temporary}/workspace.ts +1 -4
  87. package/src/tools/{web-fetch.ts → web/fetch.ts} +4 -13
  88. package/src/tools/web/index.ts +2 -0
  89. package/src/tools/web/search/api.ts +1320 -0
  90. package/src/tools/web/search/index.ts +2 -0
  91. package/src/tools/{web-search/web-search.ts → web/search/search.ts} +5 -7
  92. package/src/tools/{workspace-sandbox.ts → workspace/index.ts} +12 -272
  93. package/src/tools/{workspace-revision.ts → workspace/revision.ts} +3 -3
  94. package/src/tools/base.ts +0 -534
  95. package/src/tools/schedule.ts +0 -261
  96. package/src/tools/skill.ts +0 -565
  97. package/src/tools/web-search/api.ts +0 -1318
  98. package/src/tools/web-search/index.ts +0 -2
  99. package/src/tools/workspace-state-connector.ts +0 -146
  100. package/src/tools/{approval → runtime/approval}/index.ts +0 -0
  101. package/src/tools/{interaction → runtime/interaction}/index.ts +0 -0
  102. package/src/tools/{temporary-agent → subagent/temporary}/coordinator.ts +0 -0
  103. package/src/tools/{subagent-types → subagent/types}/contract.ts +0 -0
  104. package/src/tools/{subagent-types → subagent/types}/extract/index.ts +0 -0
  105. package/src/tools/{subagent-types → subagent/types}/fanout/index.ts +0 -0
  106. package/src/tools/{subagent-types → subagent/types}/registry.ts +1 -1
  107. /package/src/tools/{workspace-versioning.ts → workspace/versioning.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@springbrand/agent-runtime",
3
- "version": "0.3.0-alpha.1",
3
+ "version": "0.3.0-alpha.10",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -13,14 +13,14 @@
13
13
  ".": "./src/index.ts",
14
14
  "./adapter/cloudflare": "./src/adapter/cloudflare/index.ts",
15
15
  "./contracts": "./src/config/public-contracts.ts",
16
- "./declared-tool": "./src/tools/declared.ts",
16
+ "./declared-tool": "./src/tools/adapters/declared.ts",
17
17
  "./models": "./src/lib/model-catalog.ts"
18
18
  },
19
19
  "dependencies": {
20
- "@cloudflare/codemode": "0.5.1",
20
+ "@cloudflare/codemode": "0.5.2",
21
21
  "@cloudflare/sandbox": "0.12.4",
22
22
  "@cloudflare/shell": "0.4.3",
23
- "@cloudflare/think": "0.17.0",
23
+ "@cloudflare/think": "0.18.0",
24
24
  "@earendil-works/pi-agent-core": "0.85.1",
25
25
  "@earendil-works/pi-ai": "0.85.1",
26
26
  "@types/lodash-es": "^4.17.12",
@@ -30,11 +30,11 @@
30
30
  "zod": "^4.4.3"
31
31
  },
32
32
  "peerDependencies": {
33
- "agents": "^0.22.0",
33
+ "agents": "^0.23.0",
34
34
  "ai": "^7.0.0"
35
35
  },
36
36
  "devDependencies": {
37
- "agents": "0.22.0",
37
+ "agents": "0.23.0",
38
38
  "ai": "7.0.56"
39
39
  }
40
40
  }
@@ -33,6 +33,7 @@ import {
33
33
  type SubmissionReceipt,
34
34
  type SubmissionExecutionMode,
35
35
  type SubmissionHandle,
36
+ type RuntimeUnattendedExecutionGrant,
36
37
  } from "../../submission";
37
38
  import type { ExecutionLevel } from "../../lib/execution-level";
38
39
  import {
@@ -98,6 +99,10 @@ import { RuntimeDatabase } from "./database";
98
99
  // #region Runtime 内部数据与基础工具
99
100
 
100
101
  const SCHEDULED_STABLE_TIMEOUT_MS = 30_000;
102
+ /** 定时 Run 未结束时拒绝普通输入的统一原因,服务端与客户端状态共用同一事实。 */
103
+ const SCHEDULED_INPUT_LOCKED_MESSAGE =
104
+ "This scheduled run is still in progress. Wait for it to finish before sending a message.";
105
+
101
106
  interface ActiveTurn {
102
107
  submissionId: string;
103
108
  requestId: string;
@@ -390,7 +395,7 @@ export abstract class AgentRuntimeKernel<
390
395
  }
391
396
  await this.broadcastApprovals();
392
397
  const running = this.db.submissions.findRunning() as StoredSubmission | null;
393
- if (running) {
398
+ if (running && !running.unattendedFailure) {
394
399
  if (
395
400
  this.db.approvals.listPendingForSubmission(running.submissionId).length > 0 ||
396
401
  this.db.interactions.listPendingForSubmission(running.submissionId).length > 0
@@ -513,11 +518,15 @@ export abstract class AgentRuntimeKernel<
513
518
  }> {
514
519
  if (fresh) await this.prepareRuntimeForSubmission(submissionId);
515
520
  else await this.ensureRuntimeReady();
516
- return this.currentAssemblyPin();
521
+ const submission = this.db.submissions.find(submissionId);
522
+ if (!submission) {
523
+ throw new Error(`Unknown SpringBrand submission: ${submissionId}`);
524
+ }
525
+ return this.currentAssemblyPin(submission.origin !== "scheduled");
517
526
  }
518
527
 
519
528
  // initConfig can call this inside its serialized load; re-entering ensureRuntimeReady would deadlock.
520
- private async currentAssemblyPin(): Promise<{
529
+ private async currentAssemblyPin(includeMemory = true): Promise<{
521
530
  revision: string;
522
531
  descriptor: string;
523
532
  }> {
@@ -526,16 +535,18 @@ export abstract class AgentRuntimeKernel<
526
535
  if (!runtime) {
527
536
  throw new Error("Runtime revision is not initialized");
528
537
  }
529
- return this.pinAssembly(runtime.pi, runtime.revision);
538
+ return this.pinAssembly(runtime.pi, runtime.revision, includeMemory);
530
539
  }
531
540
 
532
541
  private async pinAssembly(
533
542
  prepared: PreparedPiRuntime,
534
543
  baseRevision: string,
544
+ includeMemory: boolean,
535
545
  ): Promise<{ revision: string; descriptor: string }> {
536
546
  const pinned = await this.pi.pin({
537
547
  prepared,
538
548
  baseRevision,
549
+ includeMemory,
539
550
  readExtensionContext: ({ label }) =>
540
551
  this._hostGetContext(label),
541
552
  });
@@ -668,11 +679,13 @@ export abstract class AgentRuntimeKernel<
668
679
  return submission;
669
680
  }
670
681
  if (submission.abortReason && submission.status === "pending") {
671
- return this.submissions.finish(
682
+ const terminal = await this.submissions.finish(
672
683
  submission,
673
684
  "aborted",
674
685
  submission.abortReason,
675
686
  );
687
+ await this.projectTerminal(terminal);
688
+ return terminal;
676
689
  }
677
690
  if (mode === "recovery") {
678
691
  this.telemetry.capture("turnRecovering", {
@@ -683,7 +696,11 @@ export abstract class AgentRuntimeKernel<
683
696
  await this.broadcastApprovals();
684
697
  }
685
698
  try {
686
- return await this.executeHarnessSubmission(submission, mode);
699
+ const outcome = await this.executeHarnessSubmission(submission, mode);
700
+ if (isTerminalSubmissionStatus(outcome.status)) {
701
+ await this.projectTerminal(outcome);
702
+ }
703
+ return outcome;
687
704
  } catch (error) {
688
705
  const failed = await this.submissions.finish(
689
706
  submission,
@@ -697,10 +714,57 @@ export abstract class AgentRuntimeKernel<
697
714
  : undefined,
698
715
  mode !== "fresh",
699
716
  );
717
+ await this.projectTerminal(failed);
700
718
  return failed;
701
719
  }
702
720
  }
703
721
 
722
+ /** Project one authoritative Submission terminal after Harness and client settlement. */
723
+ private async projectTerminal(submission: StoredSubmission): Promise<void> {
724
+ if (!isTerminalSubmissionStatus(submission.status)) {
725
+ throw new Error(`Cannot project unfinished Submission: ${submission.submissionId}`);
726
+ }
727
+ const events = this.activeRuntime?.snapshot.bindings.turnEvents;
728
+ if (!events) return;
729
+ const messages = await this.getMessages();
730
+ try {
731
+ await events.onResponse(
732
+ messages.flatMap((message) =>
733
+ message.role === "user" || message.role === "assistant"
734
+ ? [{
735
+ role: message.role,
736
+ text: message.parts
737
+ .filter(
738
+ (
739
+ part,
740
+ ): part is Extract<UIMessage["parts"][number], { type: "text" }> =>
741
+ part.type === "text",
742
+ )
743
+ .map((part) => part.text)
744
+ .join(""),
745
+ }]
746
+ : []
747
+ ),
748
+ );
749
+ } catch (error) {
750
+ console.warn("[runtime-turn-projection:degraded]", json({
751
+ error: errorText(error),
752
+ }));
753
+ }
754
+ try {
755
+ await events.onSubmissionTerminal?.({
756
+ submissionId: submission.submissionId,
757
+ status: submission.status,
758
+ ...(submission.error ? { error: submission.error } : {}),
759
+ resultMessageId: submission.assistantMessageId,
760
+ });
761
+ } catch (error) {
762
+ console.warn("[runtime-terminal-projection:degraded]", json({
763
+ error: errorText(error),
764
+ }));
765
+ }
766
+ }
767
+
704
768
  /** Run or recover the Submission through Pi's single durable AgentHarness. */
705
769
  private async executeHarnessSubmission(
706
770
  submission: StoredSubmission,
@@ -722,6 +786,17 @@ export abstract class AgentRuntimeKernel<
722
786
  onGeneration: (event) => this.telemetry.generation(submissionId, event),
723
787
  },
724
788
  );
789
+ const prepareToolInput = (toolName: string, input: unknown): unknown => {
790
+ const prepare = harnessInput.candidates.find(({ tool }) =>
791
+ tool.name === toolName
792
+ )?.tool.prepareArguments;
793
+ if (!prepare) return input;
794
+ try {
795
+ return prepare(input);
796
+ } catch {
797
+ return input;
798
+ }
799
+ };
725
800
  let runtime!: Awaited<ReturnType<typeof openSessionHarness>>;
726
801
  let publishApprovalRequest = async (
727
802
  _toolCallId: string,
@@ -732,6 +807,8 @@ export abstract class AgentRuntimeKernel<
732
807
  submissionId,
733
808
  requestId: submission.requestId,
734
809
  executionLevel: activeRuntime.snapshot.profile.executionLevel,
810
+ origin: submission.origin,
811
+ scheduledMaxExecutionLevel: submission.scheduledMaxExecutionLevel ?? undefined,
735
812
  },
736
813
  candidates: harnessInput.candidates,
737
814
  telemetry: this.telemetry,
@@ -759,6 +836,10 @@ export abstract class AgentRuntimeKernel<
759
836
  }
760
837
  },
761
838
  gateTool: harnessInput.platform.gateTool,
839
+ onUnattendedFailure: (reason) => {
840
+ this.db.submissions.recordUnattendedFailure(submissionId, reason);
841
+ },
842
+ unattendedFailure: () => this.db.submissions.find(submissionId)?.unattendedFailure,
762
843
  });
763
844
  runtime = await openSessionHarness({
764
845
  session: openCloudflareSession(this.ctx.storage),
@@ -771,6 +852,7 @@ export abstract class AgentRuntimeKernel<
771
852
  workspace: harnessInput.workspace,
772
853
  authorize: gate.authorize.bind(gate),
773
854
  resolveReplay: gate.resolveReplay.bind(gate),
855
+ resolveConfirmation: gate.resolveConfirmation.bind(gate),
774
856
  }),
775
857
  modelToolResultExemptions: harnessInput.candidates
776
858
  .filter(({ outputBudget }) => outputBudget?.kind === "structure")
@@ -783,14 +865,26 @@ export abstract class AgentRuntimeKernel<
783
865
  let stream: ReturnType<typeof bindHarnessStream> | undefined;
784
866
  let deactivate = () => {};
785
867
  try {
868
+ runtime.harness.hooks.on("after_response", ({ message }) => {
869
+ for (const part of message.content) {
870
+ if (part.type === "toolCall") {
871
+ part.arguments = prepareToolInput(
872
+ part.name,
873
+ part.arguments,
874
+ ) as Record<string, unknown>;
875
+ }
876
+ }
877
+ return { message };
878
+ });
786
879
  runtime.harness.hooks.on("before_tool", gate.beforeTool);
787
880
  runtime.harness.hooks.on("before_drive", async (event, context) => {
788
- if (this.db.submissions.find(submissionId)?.abortReason) {
881
+ const current = this.db.submissions.find(submissionId);
882
+ if (current?.abortReason || current?.unattendedFailure) {
789
883
  await runtime.requestAbort(event.runId, context);
790
884
  }
791
885
  });
792
886
 
793
- if (submission.abortReason && runtime.openOperation) {
887
+ if ((submission.abortReason || submission.unattendedFailure) && runtime.openOperation) {
794
888
  await runtime.requestAbort(
795
889
  runtime.openOperation.operationId,
796
890
  BACKGROUND_CONTEXT,
@@ -807,11 +901,15 @@ export abstract class AgentRuntimeKernel<
807
901
  );
808
902
  if (preparation.kind === "settled") {
809
903
  const record = preparation.outcome;
904
+ const unattendedFailure = this.db.submissions.find(submissionId)
905
+ ?.unattendedFailure;
810
906
  const terminal = await this.submissions.finish(
811
907
  submission,
812
- record.status === "completed" || record.status === "declined"
908
+ unattendedFailure
909
+ ? "failed"
910
+ : record.status === "completed" || record.status === "declined"
813
911
  ? "succeeded" : record.status === "aborted" ? "aborted" : "failed",
814
- record.error?.message,
912
+ unattendedFailure ?? record.error?.message,
815
913
  );
816
914
  this.broadcast(json({
817
915
  type: MessageType.CF_AGENT_CHAT_MESSAGES,
@@ -870,6 +968,7 @@ export abstract class AgentRuntimeKernel<
870
968
  userMessageId: submission.userMessageId ?? undefined,
871
969
  startedAt: submission.createdAt,
872
970
  turnId: submissionId,
971
+ prepareToolInput,
873
972
  publish: async (chunks) => {
874
973
  for (const chunk of chunks) {
875
974
  this.conversation.broadcastResponse({
@@ -936,7 +1035,11 @@ export abstract class AgentRuntimeKernel<
936
1035
  return this.db.submissions.find(submissionId)!;
937
1036
  }
938
1037
  const record = outcome.outcome;
939
- const status = record.status === "completed" || record.status === "declined"
1038
+ const unattendedFailure = this.db.submissions.find(submissionId)
1039
+ ?.unattendedFailure;
1040
+ const status = unattendedFailure
1041
+ ? "failed"
1042
+ : record.status === "completed" || record.status === "declined"
940
1043
  ? "succeeded"
941
1044
  : record.status === "aborted"
942
1045
  ? "aborted"
@@ -945,7 +1048,7 @@ export abstract class AgentRuntimeKernel<
945
1048
  const terminal = await this.submissions.finish(
946
1049
  submission,
947
1050
  status,
948
- record.error?.message,
1051
+ unattendedFailure ?? record.error?.message,
949
1052
  );
950
1053
  const projectedOutcome = projectSubmissionOutcome(record, terminal);
951
1054
  await stream.flushTerminal(projectedOutcome);
@@ -1270,11 +1373,41 @@ export abstract class AgentRuntimeKernel<
1270
1373
  this.transcript.importSnapshot(snapshot);
1271
1374
  }
1272
1375
 
1376
+ /**
1377
+ * 本 Session 是否有一条未结束的定时 Submission。
1378
+ *
1379
+ * 定时 Run 未结束时独占输入:普通消息在准入前被拒绝,不排队等它结束。
1380
+ * 定时注入本身走 `submitScheduledPrompt`,不经过这道闸。
1381
+ */
1382
+ private get scheduledInputLocked(): boolean {
1383
+ return this.db.submissions.hasUnfinishedScheduled();
1384
+ }
1385
+
1386
+ private rejectedOrdinaryInputReceipt(): SubmissionReceipt {
1387
+ return {
1388
+ submissionId: crypto.randomUUID(),
1389
+ status: "skipped",
1390
+ accepted: false,
1391
+ error: SCHEDULED_INPUT_LOCKED_MESSAGE,
1392
+ retryable: false,
1393
+ createdAt: Date.now(),
1394
+ };
1395
+ }
1396
+
1397
+ private rejectInputLocked(): MessageDispatchReceipt {
1398
+ return {
1399
+ kind: "rejected",
1400
+ code: "input_locked",
1401
+ message: SCHEDULED_INPUT_LOCKED_MESSAGE,
1402
+ };
1403
+ }
1404
+
1273
1405
  /** Admit text and return immediately; completion continues in the Durable Object. */
1274
1406
  async submitPrompt(
1275
1407
  text: string,
1276
1408
  options?: { idempotencyKey?: string },
1277
1409
  ): Promise<SubmissionReceipt> {
1410
+ if (this.scheduledInputLocked) return this.rejectedOrdinaryInputReceipt();
1278
1411
  const submitted = await this.submitMessage({
1279
1412
  role: "user",
1280
1413
  content: [{ type: "text", text }],
@@ -1304,17 +1437,24 @@ export abstract class AgentRuntimeKernel<
1304
1437
  }
1305
1438
 
1306
1439
  async dispatchMessage(message: UIMessage, delivery: MessageDelivery): Promise<MessageDispatchReceipt> {
1440
+ if (this.scheduledInputLocked) return this.rejectInputLocked();
1307
1441
  return this.delivery.dispatch(message, delivery);
1308
1442
  }
1309
1443
 
1310
1444
  async steerQueuedSubmission(submissionId: string): Promise<MessageDispatchReceipt> {
1445
+ if (this.scheduledInputLocked) return this.rejectInputLocked();
1311
1446
  return this.delivery.steerQueued(submissionId);
1312
1447
  }
1313
1448
 
1314
1449
  /** Admit scheduled work after a bounded stable wait, otherwise return skipped. */
1315
1450
  async submitScheduledPrompt(
1316
1451
  prompt: string,
1317
- options?: { idempotencyKey?: string },
1452
+ options?: {
1453
+ idempotencyKey?: string;
1454
+ scheduledMaxExecutionLevel?: ExecutionLevel;
1455
+ /** @deprecated Retained for rolling upgrades; ignored by Runtime. */
1456
+ unattendedExecutionGrant?: RuntimeUnattendedExecutionGrant;
1457
+ },
1318
1458
  ): Promise<SubmissionReceipt> {
1319
1459
  const requestId = crypto.randomUUID();
1320
1460
  const submitted = await this.submitMessageWhenStable(
@@ -1326,6 +1466,8 @@ export abstract class AgentRuntimeKernel<
1326
1466
  {
1327
1467
  requestId,
1328
1468
  idempotencyKey: options?.idempotencyKey,
1469
+ origin: "scheduled",
1470
+ scheduledMaxExecutionLevel: options?.scheduledMaxExecutionLevel,
1329
1471
  },
1330
1472
  SCHEDULED_STABLE_TIMEOUT_MS,
1331
1473
  );
@@ -1410,7 +1552,7 @@ export abstract class AgentRuntimeKernel<
1410
1552
  summary: approval.summary,
1411
1553
  executionLevel: approval.executionLevel,
1412
1554
  requiredExecutionLevel: approval.requiredExecutionLevel,
1413
- inputJson: approval.inputJson,
1555
+ inputJson: approval.confirmationJson ?? approval.inputJson,
1414
1556
  requestId: approval.requestId,
1415
1557
  };
1416
1558
  }
@@ -1520,6 +1662,7 @@ export abstract class AgentRuntimeKernel<
1520
1662
  hasPendingInteraction: (id) => this.humanDecisions.isWaitingForInteraction(id),
1521
1663
  hasPendingSteer: (id) => this.db.steers.listForSubmission(id).length > 0,
1522
1664
  hasRunningAgentTools: this.db.agentTools.hasRunning(),
1665
+ hasUnfinishedScheduled: this.db.submissions.hasUnfinishedScheduled(),
1523
1666
  previousState: this.state,
1524
1667
  });
1525
1668
  if (changed) this.setState(state);
@@ -114,7 +114,7 @@ interface RuntimeAgentDefinitionBase<
114
114
  /** Prepare the optional telemetry consumer for this concrete Agent facet. */
115
115
  readonly telemetry?: (
116
116
  context: RuntimeAgentPlanningContext<Env, Command, Change>,
117
- ) => AgentTelemetryBinding | undefined;
117
+ ) => AgentTelemetryBinding | undefined | Promise<AgentTelemetryBinding | undefined>;
118
118
  }
119
119
 
120
120
  export interface ReadonlyRuntimeAgentDefinition<
@@ -262,7 +262,12 @@ export interface RuntimeAgentControls {
262
262
  */
263
263
  submitScheduledPrompt(
264
264
  prompt: string,
265
- opts?: { idempotencyKey?: string },
265
+ opts?: {
266
+ idempotencyKey?: string;
267
+ scheduledMaxExecutionLevel?: import("../../lib/execution-level").ExecutionLevel;
268
+ /** @deprecated Retained for rolling upgrades; ignored by Runtime. */
269
+ unattendedExecutionGrant?: import("../../submission").RuntimeUnattendedExecutionGrant;
270
+ },
266
271
  ): Promise<SubmissionReceipt>;
267
272
  /**
268
273
  * 按提交编号查询当前处理状态。
@@ -406,14 +411,14 @@ export function defineRuntimeAgent<
406
411
  | MutableRuntimeAgentDefinition<Env, Config, Command, Change>
407
412
  | ReadonlyRuntimeAgentDefinition<Env, Config>,
408
413
  ): RuntimeAgentClass<Env, Command, Change> {
409
- const resolveDefinitionTelemetry = (
414
+ const resolveDefinitionTelemetry = async (
410
415
  context: RuntimeAgentPlanningContext<Env, Command, Change>,
411
- ): AgentTelemetryBinding | undefined => {
416
+ ): Promise<AgentTelemetryBinding | undefined> => {
412
417
  const telemetry = definition.telemetry;
413
418
  if (!telemetry) return undefined;
414
- return (telemetry as (
419
+ return await (telemetry as (
415
420
  context: RuntimeAgentPlanningContext<Env, Command, Change>,
416
- ) => AgentTelemetryBinding | undefined)(context);
421
+ ) => AgentTelemetryBinding | undefined | Promise<AgentTelemetryBinding | undefined>)(context);
417
422
  };
418
423
 
419
424
  const GeneratedRuntimeAgent = {
@@ -635,7 +640,7 @@ export function defineRuntimeAgent<
635
640
  let resources = loaded.resources;
636
641
  let commitGuard = loaded.commitGuard;
637
642
  if (!this.telemetryResolved) {
638
- this.resolvedTelemetry = resolveDefinitionTelemetry(context);
643
+ this.resolvedTelemetry = await resolveDefinitionTelemetry(context);
639
644
  this.telemetryResolved = true;
640
645
  }
641
646
  const telemetry = this.resolvedTelemetry;
@@ -23,8 +23,26 @@ export {
23
23
  export {
24
24
  isValidTimeZone,
25
25
  nextCronOccurrence,
26
+ wallTimeInstants,
26
27
  zoneOffsetMs,
27
28
  } from "./scheduling/zoned-cron";
29
+ export {
30
+ DEFAULT_LATENESS_WINDOW_MS,
31
+ isWithinLatenessWindow,
32
+ nextScheduledOccurrence,
33
+ resolveScheduleOccurrences,
34
+ toScheduleRuleSpec,
35
+ validateScheduleRuleSpec,
36
+ type LocalScheduleTrigger,
37
+ type ScheduledOccurrence,
38
+ type ScheduleOccurrence,
39
+ type ScheduleOccurrenceResolution,
40
+ type ScheduleRuleError,
41
+ type ScheduleRuleErrorCode,
42
+ type ScheduleRuleSpec,
43
+ type ScheduleSkipReason,
44
+ type SkippedOccurrence,
45
+ } from "./scheduling/schedule-rule";
28
46
 
29
47
  export {
30
48
  CloudflareSandboxAdapter,