@rivus/agent 0.6.2 → 0.8.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.
package/dist/index.js CHANGED
@@ -1,13 +1,15 @@
1
1
  import { a as createAgentLoopSkillExecutionStart, c as createAgentLoopToolExecutionEnd, d as createAsyncIterableAgentLoop, f as createEventAgentLoop, i as createAgentLoopSkillExecutionEnd, l as createAgentLoopToolExecutionStart, m as createTextAgentLoopFromCallback, n as createAgentLoopModelExecutionEnd, o as createAgentLoopTextDelta, p as createTextAgentLoop, r as createAgentLoopModelExecutionStart, s as createAgentLoopThinkingDelta, t as createAgentLoopFromCallback, u as createAgentLoopToolExecutionUpdate } from "./agent-loop.js";
2
2
  import { a as createMemoryNamespace, c as InvalidRivusPlugin, d as requiresToolApproval, i as RIVUS_MEMORY_TOOL_VERSION, l as RIVUS_PLUGIN_API_VERSION, n as RIVUS_MEMORY_TOOL_ID, o as createRivusMemoryToolContract, r as RIVUS_MEMORY_TOOL_PLUGIN_ID, s as restrictMemoryScopesForAudience, t as MEMORY_SCOPES, u as RivusToolInputRejected } from "./agent-memory.js";
3
+ import { a as BACKGROUND_SESSION_TOOL_VERSION, c as createBackgroundSessionStepSourceMessageId, d as isBackgroundSessionToolId, f as narrowBackgroundSessionDefinition, i as BACKGROUND_SESSION_TOOL_PLUGIN_ID, l as createBackgroundSessionToolContracts, n as BACKGROUND_SESSION_START_TOOL_ID, o as backgroundSessionToolIds, r as BACKGROUND_SESSION_TOOL_IDS, s as createBackgroundSessionKey, t as BACKGROUND_SESSION_SESSION_KEY_PREFIX, u as extendBackgroundSessionDefinition } from "./background-session-authority.js";
3
4
  import { n as resolveRivusAgentDefinition, t as createRivusPluginCatalog } from "./rivus-plugin-registry.js";
4
- import { A as CardPresentationTransitionDenied, B as FeishuEndpointCredentialError, C as loadRivusDaemonConfig, D as loadRivusDeploymentManifest, E as RivusDeploymentManifestError, F as completeCardPresentationHandoff, G as validateRivusDeploymentManifest, I as createCardPresentationChain, L as failCardPresentationHandoff, M as activeCardPresentation, N as beginCardPresentationHandoff, O as DEFAULT_CARD_STREAM_LEASE_MS, P as compensateCardPresentationHandoff, R as isCardPresentationHandoffDue, S as RivusDaemonConfigError, U as RivusPluginLoadError, V as resolveFeishuEndpointCredentials, W as loadRivusDeployment, _ as createStableId, a as InvalidRivusProjectSpace, b as createRivusEnvFromOpenClawConfig, c as RivusDeploymentReadinessError, d as createRivusAgentHost, f as AgentInstanceBusy, g as createAgentInstanceRegistry, h as AgentInstanceConflict, i as resolveRivusProjectSpace, j as acceptsCardPresentationProgress, k as createFeishuCardRollover, l as createRivusDeploymentDaemon, m as createAgentRuntimePool, n as createRivusDeploymentCliProcess, o as RivusDeploymentAutomationReadinessError, p as AgentRuntimeDisposed, r as createConfiguredRivusDeploymentDaemon, s as RivusDeploymentDaemonLifecycleError, t as runRivusDaemonCli, u as InvalidRivusEndpointBinding, v as createRivusDaemonShutdownController, w as loadNodeRivusPluginModule, x as formatRivusEnvFile, y as OpenClawEnvImportError, z as markCardPresentationTerminal } from "./rivus-daemon-cli.js";
5
+ import { $ as loadRivusDeployment, A as DEFAULT_BACKGROUND_SESSION_LIFETIME_MS, B as acceptsCardPresentationProgress, C as loadRivusDaemonConfig, D as loadRivusDeploymentManifest, E as RivusDeploymentManifestError, F as DEFAULT_BACKGROUND_SESSION_SUPERVISOR_INTERVAL_MS, G as createCardPresentationChain, H as beginCardPresentationHandoff, I as resolveBackgroundSessionSupervisorIntervalMs, J as markCardPresentationTerminal, K as failCardPresentationHandoff, L as DEFAULT_CARD_STREAM_LEASE_MS, M as DEFAULT_BACKGROUND_SESSION_MAX_CONSECUTIVE_FAILURES, N as DEFAULT_BACKGROUND_SESSION_RETRY_BACKOFF_MS, O as DEFAULT_BACKGROUND_SESSION_LEASE_MS, P as DEFAULT_BACKGROUND_SESSION_STEP_TIMEOUT_MS, Q as RivusPluginLoadError, R as createFeishuCardRollover, S as RivusDaemonConfigError, U as compensateCardPresentationHandoff, V as activeCardPresentation, W as completeCardPresentationHandoff, X as resolveFeishuEndpointCredentials, Y as FeishuEndpointCredentialError, _ as createStableId, a as InvalidRivusProjectSpace, b as createRivusEnvFromOpenClawConfig, c as RivusDeploymentReadinessError, d as createRivusAgentHost, et as validateRivusDeploymentManifest, f as AgentInstanceBusy, g as createAgentInstanceRegistry, h as AgentInstanceConflict, i as resolveRivusProjectSpace, j as DEFAULT_BACKGROUND_SESSION_MAX_CONCURRENT_SESSIONS, k as DEFAULT_BACKGROUND_SESSION_LEASE_RENEWAL_INTERVAL_MS, l as createRivusDeploymentDaemon, m as createAgentRuntimePool, n as createRivusDeploymentCliProcess, o as RivusDeploymentAutomationReadinessError, p as AgentRuntimeDisposed, q as isCardPresentationHandoffDue, r as createConfiguredRivusDeploymentDaemon, s as RivusDeploymentDaemonLifecycleError, t as runRivusDaemonCli, u as InvalidRivusEndpointBinding, v as createRivusDaemonShutdownController, w as loadNodeRivusPluginModule, x as formatRivusEnvFile, y as OpenClawEnvImportError, z as CardPresentationTransitionDenied } from "./rivus-daemon-cli.js";
5
6
  import { a as InvalidInvocationAuthority, i as normalizeStableJson, n as InvalidToolInput, o as createInvocationAuthority, r as createToolInputDigest, s as resolveInvocationAuthority, t as InvalidStableJson } from "./tool-input-digest.js";
7
+ import { a as readBackgroundSessionWaitInput, i as readBackgroundSessionString, n as readBackgroundSessionObject, r as readBackgroundSessionPhase, t as readBackgroundSessionInteger } from "./background-session-input.js";
6
8
  import { n as assertRivusPluginConforms, r as createFakeRivusPlugin, t as RivusPluginConformanceError } from "./rivus-plugin-testkit.js";
7
9
  import { Cause, Deferred, Effect, Either, Exit, Fiber, Option, Stream } from "effect";
8
10
  import { createHash, randomUUID } from "node:crypto";
9
11
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
10
- import { appendFile, lstat, mkdir, readFile, readdir, realpath, rename, stat, unlink, writeFile } from "node:fs/promises";
12
+ import { appendFile, lstat, mkdir, readFile, readdir, realpath, rename, stat, truncate, unlink, writeFile } from "node:fs/promises";
11
13
  import { isDeepStrictEqual } from "node:util";
12
14
  import { createServer } from "node:http";
13
15
  import { Buffer as Buffer$1 } from "node:buffer";
@@ -3443,36 +3445,36 @@ function parseAgentDomainEvent(value, lineNumber) {
3443
3445
  switch (value.type) {
3444
3446
  case "agent_run_accepted": return {
3445
3447
  occurredAt,
3446
- prompt: readString(value, "prompt", lineNumber),
3447
- runId: readString(value, "runId", lineNumber),
3448
- sessionKey: readString(value, "sessionKey", lineNumber),
3448
+ prompt: readString$1(value, "prompt", lineNumber),
3449
+ runId: readString$1(value, "runId", lineNumber),
3450
+ sessionKey: readString$1(value, "sessionKey", lineNumber),
3449
3451
  type: value.type
3450
3452
  };
3451
3453
  case "agent_turn_started": return {
3452
3454
  occurredAt,
3453
- runId: readString(value, "runId", lineNumber),
3454
- sessionKey: readString(value, "sessionKey", lineNumber),
3455
+ runId: readString$1(value, "runId", lineNumber),
3456
+ sessionKey: readString$1(value, "sessionKey", lineNumber),
3455
3457
  type: value.type
3456
3458
  };
3457
3459
  case "assistant_text_delta": return {
3458
- delta: readString(value, "delta", lineNumber),
3460
+ delta: readString$1(value, "delta", lineNumber),
3459
3461
  occurredAt,
3460
- runId: readString(value, "runId", lineNumber),
3462
+ runId: readString$1(value, "runId", lineNumber),
3461
3463
  type: value.type
3462
3464
  };
3463
3465
  case "assistant_thinking_delta": return {
3464
- delta: readString(value, "delta", lineNumber),
3466
+ delta: readString$1(value, "delta", lineNumber),
3465
3467
  occurredAt,
3466
- runId: readString(value, "runId", lineNumber),
3468
+ runId: readString$1(value, "runId", lineNumber),
3467
3469
  type: value.type
3468
3470
  };
3469
3471
  case "agent_model_execution_started": return {
3470
- api: readString(value, "api", lineNumber),
3471
- model: readString(value, "model", lineNumber),
3472
- modelCallId: readString(value, "modelCallId", lineNumber),
3472
+ api: readString$1(value, "api", lineNumber),
3473
+ model: readString$1(value, "model", lineNumber),
3474
+ modelCallId: readString$1(value, "modelCallId", lineNumber),
3473
3475
  occurredAt,
3474
- provider: readString(value, "provider", lineNumber),
3475
- runId: readString(value, "runId", lineNumber),
3476
+ provider: readString$1(value, "provider", lineNumber),
3477
+ runId: readString$1(value, "runId", lineNumber),
3476
3478
  type: value.type
3477
3479
  };
3478
3480
  case "agent_model_execution_ended": {
@@ -3481,15 +3483,15 @@ function parseAgentDomainEvent(value, lineNumber) {
3481
3483
  const responseModel = readOptionalString(value, "responseModel", lineNumber);
3482
3484
  const reasoning = readOptionalNumber(usage, "reasoning", lineNumber);
3483
3485
  return {
3484
- api: readString(value, "api", lineNumber),
3486
+ api: readString$1(value, "api", lineNumber),
3485
3487
  ...errorMessage ? { errorMessage } : {},
3486
- model: readString(value, "model", lineNumber),
3487
- modelCallId: readString(value, "modelCallId", lineNumber),
3488
+ model: readString$1(value, "model", lineNumber),
3489
+ modelCallId: readString$1(value, "modelCallId", lineNumber),
3488
3490
  occurredAt,
3489
- provider: readString(value, "provider", lineNumber),
3491
+ provider: readString$1(value, "provider", lineNumber),
3490
3492
  ...responseModel ? { responseModel } : {},
3491
- runId: readString(value, "runId", lineNumber),
3492
- stopReason: readString(value, "stopReason", lineNumber),
3493
+ runId: readString$1(value, "runId", lineNumber),
3494
+ stopReason: readString$1(value, "stopReason", lineNumber),
3493
3495
  type: value.type,
3494
3496
  usage: {
3495
3497
  cacheRead: readNumber(usage, "cacheRead", lineNumber),
@@ -3519,10 +3521,10 @@ function parseAgentDomainEvent(value, lineNumber) {
3519
3521
  } : {
3520
3522
  ...common,
3521
3523
  contentLength: readNumber(value, "contentLength", lineNumber),
3522
- digest: readString(value, "digest", lineNumber),
3524
+ digest: readString$1(value, "digest", lineNumber),
3523
3525
  isError: false,
3524
- title: readString(value, "title", lineNumber),
3525
- version: readString(value, "version", lineNumber)
3526
+ title: readString$1(value, "title", lineNumber),
3527
+ version: readString$1(value, "version", lineNumber)
3526
3528
  };
3527
3529
  }
3528
3530
  case "agent_tool_execution_started": return {
@@ -3546,21 +3548,21 @@ function parseAgentDomainEvent(value, lineNumber) {
3546
3548
  type: value.type
3547
3549
  };
3548
3550
  case "agent_turn_completed": return {
3549
- finalText: readString(value, "finalText", lineNumber),
3551
+ finalText: readString$1(value, "finalText", lineNumber),
3550
3552
  occurredAt,
3551
- runId: readString(value, "runId", lineNumber),
3553
+ runId: readString$1(value, "runId", lineNumber),
3552
3554
  type: value.type
3553
3555
  };
3554
3556
  case "agent_run_completed": return {
3555
- finalText: readString(value, "finalText", lineNumber),
3557
+ finalText: readString$1(value, "finalText", lineNumber),
3556
3558
  occurredAt,
3557
- runId: readString(value, "runId", lineNumber),
3559
+ runId: readString$1(value, "runId", lineNumber),
3558
3560
  type: value.type
3559
3561
  };
3560
3562
  case "agent_run_failed": return {
3561
- errorMessage: readString(value, "errorMessage", lineNumber),
3563
+ errorMessage: readString$1(value, "errorMessage", lineNumber),
3562
3564
  occurredAt,
3563
- runId: readString(value, "runId", lineNumber),
3565
+ runId: readString$1(value, "runId", lineNumber),
3564
3566
  type: value.type
3565
3567
  };
3566
3568
  case "agent_run_cancelled": {
@@ -3568,7 +3570,7 @@ function parseAgentDomainEvent(value, lineNumber) {
3568
3570
  return {
3569
3571
  occurredAt,
3570
3572
  ...reason ? { reason } : {},
3571
- runId: readString(value, "runId", lineNumber),
3573
+ runId: readString$1(value, "runId", lineNumber),
3572
3574
  type: value.type
3573
3575
  };
3574
3576
  }
@@ -3577,19 +3579,19 @@ function parseAgentDomainEvent(value, lineNumber) {
3577
3579
  }
3578
3580
  function readSkillExecutionIdentity(value, lineNumber) {
3579
3581
  return {
3580
- runId: readString(value, "runId", lineNumber),
3581
- skillCallId: readString(value, "skillCallId", lineNumber),
3582
- skillId: readString(value, "skillId", lineNumber)
3582
+ runId: readString$1(value, "runId", lineNumber),
3583
+ skillCallId: readString$1(value, "skillCallId", lineNumber),
3584
+ skillId: readString$1(value, "skillId", lineNumber)
3583
3585
  };
3584
3586
  }
3585
3587
  function readToolExecutionIdentity(value, lineNumber) {
3586
3588
  return {
3587
- runId: readString(value, "runId", lineNumber),
3588
- toolCallId: readString(value, "toolCallId", lineNumber),
3589
- toolName: readString(value, "toolName", lineNumber)
3589
+ runId: readString$1(value, "runId", lineNumber),
3590
+ toolCallId: readString$1(value, "toolCallId", lineNumber),
3591
+ toolName: readString$1(value, "toolName", lineNumber)
3590
3592
  };
3591
3593
  }
3592
- function readString(value, field, lineNumber) {
3594
+ function readString$1(value, field, lineNumber) {
3593
3595
  const fieldValue = value[field];
3594
3596
  if (typeof fieldValue !== "string") throw new Error(`Invalid agent event field '${field}' at line ${lineNumber}.`);
3595
3597
  return fieldValue;
@@ -4760,7 +4762,7 @@ function unwrapResult(value) {
4760
4762
  }
4761
4763
  function presentResult(toolName, value) {
4762
4764
  if (isTruncated(value)) return "结果过长,已省略。";
4763
- if (!isRecord(value)) return truncate(presentValue(value) ?? "工具执行完成。", 2e3);
4765
+ if (!isRecord(value)) return truncate$1(presentValue(value) ?? "工具执行完成。", 2e3);
4764
4766
  const tool = resolveTool(toolName);
4765
4767
  const orderedKeys = tool.fields?.map(([key]) => key) ?? [];
4766
4768
  const lines = Object.entries(value).sort(([left], [right]) => {
@@ -4772,7 +4774,7 @@ function presentResult(toolName, value) {
4772
4774
  const presented = presentValue(item, field?.[2]);
4773
4775
  return presented ? [`${clean(field?.[1] ?? humanizeKey(key), 80)}:${presented}`] : [];
4774
4776
  }).slice(0, 12);
4775
- return truncate(lines.length > 0 ? lines.join("\n") : "工具执行完成。", 2e3);
4777
+ return truncate$1(lines.length > 0 ? lines.join("\n") : "工具执行完成。", 2e3);
4776
4778
  }
4777
4779
  function presentValue(value, unit) {
4778
4780
  if (value === REDACTED || value === TRUNCATED || value === void 0) return void 0;
@@ -4796,9 +4798,9 @@ function humanizeKey(key) {
4796
4798
  return `${text.slice(0, 1).toUpperCase()}${text.slice(1)}` || "结果";
4797
4799
  }
4798
4800
  function clean(value, maxLength) {
4799
- return truncate(value.replace(/[\p{Cc}\p{Cf}]+/gu, " ").replace(/\s+/gu, " ").trim(), maxLength);
4801
+ return truncate$1(value.replace(/[\p{Cc}\p{Cf}]+/gu, " ").replace(/\s+/gu, " ").trim(), maxLength);
4800
4802
  }
4801
- function truncate(value, maxLength) {
4803
+ function truncate$1(value, maxLength) {
4802
4804
  return value.length <= maxLength ? value : `${value.slice(0, maxLength - 1)}…`;
4803
4805
  }
4804
4806
  function isRecord(value) {
@@ -5346,7 +5348,14 @@ function createToolBroker(options) {
5346
5348
  runId: authority.runId,
5347
5349
  sessionKey: authority.sessionKey,
5348
5350
  toolId: tool.id,
5349
- toolVersion: tool.version
5351
+ toolVersion: tool.version,
5352
+ ...authority.endpointId ? { origin: Object.freeze({
5353
+ ...authority.allowedActorOpenIds ? { allowedActorOpenIds: authority.allowedActorOpenIds } : { allowedActorOpenIds: Object.freeze([]) },
5354
+ endpointId: authority.endpointId,
5355
+ tenantKey: authority.tenantKey,
5356
+ ...authority.conversationId ? { conversationId: authority.conversationId } : {}
5357
+ }) } : {},
5358
+ ...authority.sourceMessageId ? { sourceMessageId: authority.sourceMessageId } : {}
5350
5359
  });
5351
5360
  const replayCompleted = (result) => "replayCompleted" in tool && tool.replayCompleted ? tool.replayCompleted(request.input, result, context) : result;
5352
5361
  if (request.operationId) {
@@ -5881,6 +5890,1464 @@ function isVisibleMemory(record) {
5881
5890
  return record.scope !== "shared-user-profile" && record.scope !== "project" || record.state === "confirmed";
5882
5891
  }
5883
5892
  //#endregion
5893
+ //#region src/domain/background-agent-session.ts
5894
+ const BACKGROUND_SESSION_TERMINAL_PHASES = /* @__PURE__ */ new Set([
5895
+ "stopped",
5896
+ "completed",
5897
+ "failed",
5898
+ "reconciliation-required"
5899
+ ]);
5900
+ function isBackgroundSessionTerminalPhase(phase) {
5901
+ return BACKGROUND_SESSION_TERMINAL_PHASES.has(phase);
5902
+ }
5903
+ var BackgroundSessionTransitionDenied = class extends Error {
5904
+ sessionId;
5905
+ name = "BackgroundSessionTransitionDenied";
5906
+ constructor(sessionId, message) {
5907
+ super(message);
5908
+ this.sessionId = sessionId;
5909
+ }
5910
+ };
5911
+ function createBackgroundSession(input) {
5912
+ if (!input.sessionId.trim()) throw new BackgroundSessionTransitionDenied(input.sessionId, "background session id must not be empty");
5913
+ if (!input.authority.sessionKey.trim()) throw new BackgroundSessionTransitionDenied(input.sessionId, "background session key must not be empty");
5914
+ if (!input.authority.agentId.trim()) throw new BackgroundSessionTransitionDenied(input.sessionId, "background session authority requires an agent id");
5915
+ if (!input.sourceMessageId.trim()) throw new BackgroundSessionTransitionDenied(input.sessionId, "background session requires a trusted source message id");
5916
+ return Object.freeze({
5917
+ authority: Object.freeze({
5918
+ ...input.authority,
5919
+ memoryScopes: Object.freeze([...input.authority.memoryScopes])
5920
+ }),
5921
+ consecutiveFailures: 0,
5922
+ createdAt: input.now,
5923
+ displayName: input.displayName,
5924
+ origin: Object.freeze({
5925
+ ...input.origin,
5926
+ allowedActorOpenIds: Object.freeze([...input.origin.allowedActorOpenIds])
5927
+ }),
5928
+ parentRunId: input.parentRunId,
5929
+ pendingInput: Object.freeze([]),
5930
+ phase: "queued",
5931
+ prompt: input.prompt,
5932
+ revision: 1,
5933
+ sessionId: input.sessionId,
5934
+ sourceMessageId: input.sourceMessageId,
5935
+ stepCount: 0,
5936
+ updatedAt: input.now,
5937
+ wakeCount: 0
5938
+ });
5939
+ }
5940
+ function claimBackgroundSession(state, input) {
5941
+ if (isBackgroundSessionTerminalPhase(state.phase)) throw new BackgroundSessionTransitionDenied(state.sessionId, `terminal ${state.phase} session cannot run again`);
5942
+ if (state.phase !== "queued" && state.phase !== "waiting") throw new BackgroundSessionTransitionDenied(state.sessionId, `background session cannot start a step while ${state.phase}`);
5943
+ if (state.wakeAt !== void 0 && state.wakeAt > input.now) throw new BackgroundSessionTransitionDenied(state.sessionId, "background session is not due");
5944
+ return next(state, {
5945
+ currentStepRunId: input.stepRunId,
5946
+ lastWakeText: input.wakeText,
5947
+ lease: input.lease,
5948
+ pendingInput: Object.freeze([]),
5949
+ phase: "running",
5950
+ stepCount: state.stepCount + 1,
5951
+ updatedAt: input.now,
5952
+ wakeAt: void 0,
5953
+ wakeCount: state.wakeCount + 1
5954
+ });
5955
+ }
5956
+ function renewBackgroundSessionLease(state, lease) {
5957
+ if (state.lease === void 0) throw new BackgroundSessionTransitionDenied(state.sessionId, "cannot renew a lease that is not held");
5958
+ if (state.lease.owner !== lease.owner || state.lease.epoch !== lease.epoch) throw new BackgroundSessionTransitionDenied(state.sessionId, "cannot renew a lease from another worker");
5959
+ return next(state, { lease });
5960
+ }
5961
+ function releaseBackgroundSessionLease(state) {
5962
+ if (state.lease === void 0) throw new BackgroundSessionTransitionDenied(state.sessionId, "no lease to release");
5963
+ return next(state, { lease: void 0 });
5964
+ }
5965
+ function suspendBackgroundSession(state, input) {
5966
+ if (state.phase !== "running") throw new BackgroundSessionTransitionDenied(state.sessionId, `background session cannot wait while ${state.phase}`);
5967
+ if (input.wakeAt !== void 0 && input.wakeAt <= input.now) throw new BackgroundSessionTransitionDenied(state.sessionId, "background session wake time must be in the future");
5968
+ return next(state, {
5969
+ currentStepRunId: void 0,
5970
+ phase: input.wakeAt === void 0 ? "input-required" : "waiting",
5971
+ updatedAt: input.now,
5972
+ ...input.wakeAt === void 0 ? {} : { wakeAt: input.wakeAt }
5973
+ });
5974
+ }
5975
+ function completeBackgroundSessionStep(state, input) {
5976
+ if (state.phase !== "running") throw new BackgroundSessionTransitionDenied(state.sessionId, `background session cannot complete while ${state.phase}`);
5977
+ return next(state, {
5978
+ consecutiveFailures: 0,
5979
+ currentStepRunId: void 0,
5980
+ lease: void 0,
5981
+ phase: "completed",
5982
+ result: {
5983
+ completedAt: input.now,
5984
+ stepRunId: input.stepRunId,
5985
+ text: input.text
5986
+ },
5987
+ updatedAt: input.now
5988
+ });
5989
+ }
5990
+ function failBackgroundSessionStep(state, input) {
5991
+ if (state.phase !== "running") throw new BackgroundSessionTransitionDenied(state.sessionId, `background session cannot fail while ${state.phase}`);
5992
+ if (input.retryable) {
5993
+ if (input.wakeAt === void 0 || input.wakeAt <= input.now) throw new BackgroundSessionTransitionDenied(state.sessionId, "retryable failure requires a future wake time");
5994
+ return next(state, {
5995
+ consecutiveFailures: state.consecutiveFailures + 1,
5996
+ currentStepRunId: void 0,
5997
+ errorMessage: input.errorMessage,
5998
+ lease: void 0,
5999
+ phase: "queued",
6000
+ updatedAt: input.now,
6001
+ wakeAt: input.wakeAt
6002
+ });
6003
+ }
6004
+ return next(state, {
6005
+ consecutiveFailures: state.consecutiveFailures + 1,
6006
+ currentStepRunId: void 0,
6007
+ errorMessage: input.errorMessage,
6008
+ lease: void 0,
6009
+ phase: "failed",
6010
+ updatedAt: input.now
6011
+ });
6012
+ }
6013
+ function requestBackgroundSessionStop(state, input) {
6014
+ if (isBackgroundSessionTerminalPhase(state.phase)) throw new BackgroundSessionTransitionDenied(state.sessionId, `terminal ${state.phase} session cannot stop`);
6015
+ if (state.phase === "stopping") throw new BackgroundSessionTransitionDenied(state.sessionId, "background session is already stopping");
6016
+ if (state.phase === "running") return next(state, {
6017
+ cancellation: {
6018
+ reason: input.reason,
6019
+ requestedAt: input.now
6020
+ },
6021
+ phase: "stopping",
6022
+ updatedAt: input.now
6023
+ });
6024
+ return next(state, {
6025
+ cancellation: {
6026
+ reason: input.reason,
6027
+ requestedAt: input.now
6028
+ },
6029
+ currentStepRunId: void 0,
6030
+ lease: void 0,
6031
+ phase: "stopped",
6032
+ updatedAt: input.now,
6033
+ wakeAt: void 0
6034
+ });
6035
+ }
6036
+ function completeBackgroundSessionStop(state, input) {
6037
+ if (state.phase !== "stopping") throw new BackgroundSessionTransitionDenied(state.sessionId, `background session cannot finish stopping while ${state.phase}`);
6038
+ return next(state, {
6039
+ currentStepRunId: void 0,
6040
+ lease: void 0,
6041
+ phase: "stopped",
6042
+ updatedAt: input.now,
6043
+ wakeAt: void 0
6044
+ });
6045
+ }
6046
+ function parkBackgroundSessionForReconciliation(state, input) {
6047
+ if (isBackgroundSessionTerminalPhase(state.phase) && state.phase !== "reconciliation-required") throw new BackgroundSessionTransitionDenied(state.sessionId, `terminal ${state.phase} session cannot be reconciled`);
6048
+ return next(state, {
6049
+ currentStepRunId: void 0,
6050
+ errorMessage: input.reason,
6051
+ lease: void 0,
6052
+ phase: "reconciliation-required",
6053
+ reconciliationNote: input.reason,
6054
+ updatedAt: input.now,
6055
+ wakeAt: void 0
6056
+ });
6057
+ }
6058
+ function resolveBackgroundSessionReconciliation(state, input) {
6059
+ if (state.phase !== "reconciliation-required") throw new BackgroundSessionTransitionDenied(state.sessionId, `background session cannot resolve while ${state.phase}`);
6060
+ if (input.outcome === "continue") return next(state, {
6061
+ errorMessage: void 0,
6062
+ phase: "queued",
6063
+ reconciliationNote: void 0,
6064
+ updatedAt: input.now,
6065
+ wakeAt: input.now
6066
+ });
6067
+ return next(state, {
6068
+ errorMessage: void 0,
6069
+ phase: "stopped",
6070
+ reconciliationNote: void 0,
6071
+ updatedAt: input.now,
6072
+ wakeAt: void 0
6073
+ });
6074
+ }
6075
+ function appendBackgroundSessionInput(state, input) {
6076
+ if (isBackgroundSessionTerminalPhase(state.phase)) throw new BackgroundSessionTransitionDenied(state.sessionId, `terminal ${state.phase} session cannot accept input`);
6077
+ return next(state, {
6078
+ pendingInput: Object.freeze([...state.pendingInput, input.message]),
6079
+ updatedAt: input.now,
6080
+ ...state.phase === "waiting" || state.phase === "input-required" ? {
6081
+ phase: "queued",
6082
+ wakeAt: input.now
6083
+ } : {}
6084
+ });
6085
+ }
6086
+ function requeueInterruptedBackgroundSessionStep(state, input) {
6087
+ if (state.phase !== "running") throw new BackgroundSessionTransitionDenied(state.sessionId, "interrupted step recovery requires a running session");
6088
+ return next(state, {
6089
+ currentStepRunId: void 0,
6090
+ lastWakeText: input.wakeText,
6091
+ lease: void 0,
6092
+ phase: "queued",
6093
+ updatedAt: input.now,
6094
+ wakeAt: input.now
6095
+ });
6096
+ }
6097
+ function isBackgroundSessionLeaseExpired(state, now) {
6098
+ return state.lease !== void 0 && state.lease.expiresAt <= now;
6099
+ }
6100
+ function isBackgroundSessionDue(state, now) {
6101
+ if (state.phase !== "queued" && state.phase !== "waiting") return false;
6102
+ return state.wakeAt === void 0 || state.wakeAt <= now;
6103
+ }
6104
+ function next(state, changes) {
6105
+ const merged = {
6106
+ ...state,
6107
+ ...changes,
6108
+ revision: state.revision + 1
6109
+ };
6110
+ for (const key of Object.keys(merged)) if (merged[key] === void 0) delete merged[key];
6111
+ return Object.freeze(merged);
6112
+ }
6113
+ function isValidBackgroundSessionTransition(previous, nextState) {
6114
+ if (nextState.sessionId !== previous.sessionId) return "session id must not change";
6115
+ if (nextState.revision !== previous.revision + 1) return "revision must increase by exactly one";
6116
+ if (nextState.authority.agentId !== previous.authority.agentId) return "authority agent must not change";
6117
+ if (nextState.authority.profileRevision !== previous.authority.profileRevision) return "authority profile revision must not change";
6118
+ if (nextState.authority.toolGrantRevision !== previous.authority.toolGrantRevision) return "authority tool grant revision must not change";
6119
+ if (nextState.authority.sessionKey !== previous.authority.sessionKey) return "authority session key must not change";
6120
+ if (nextState.origin.endpointId !== previous.origin.endpointId) return "origin endpoint must not change";
6121
+ if (nextState.origin.tenantKey !== previous.origin.tenantKey) return "origin tenant must not change";
6122
+ if (nextState.origin.conversationId !== previous.origin.conversationId) return "origin conversation must not change";
6123
+ if (nextState.parentRunId !== previous.parentRunId) return "parent run must not change";
6124
+ if (nextState.sourceMessageId !== previous.sourceMessageId) return "source message must not change";
6125
+ if (nextState.prompt !== previous.prompt) return "prompt must not change";
6126
+ if (nextState.stepCount < previous.stepCount) return "step count must not decrease";
6127
+ if (nextState.wakeCount < previous.wakeCount) return "wake count must not decrease";
6128
+ if (nextState.consecutiveFailures < previous.consecutiveFailures) {
6129
+ if (previous.consecutiveFailures > 0 && nextState.phase === "completed" && nextState.consecutiveFailures === 0) return;
6130
+ return "failure count must not decrease";
6131
+ }
6132
+ if (nextState.createdAt !== previous.createdAt) return "created time must not change";
6133
+ if (previous.phase === "running") {
6134
+ if (nextState.phase === "running") return holdsSameLease(previous, nextState) ? void 0 : "running lease owner or epoch must not change";
6135
+ if (nextState.phase === "waiting" || nextState.phase === "input-required") return holdsSameLease(previous, nextState) ? void 0 : "suspension requires the same lease";
6136
+ if (nextState.phase === "completed" && nextState.result !== void 0 && nextState.lease === void 0) return;
6137
+ if (nextState.phase === "failed" && nextState.errorMessage !== void 0 && nextState.lease === void 0) return;
6138
+ if (nextState.phase === "stopping" && nextState.cancellation !== void 0) return void 0;
6139
+ if (nextState.phase === "reconciliation-required" && nextState.lease === void 0) return void 0;
6140
+ if (nextState.phase === "queued" && nextState.lease === void 0 && nextState.wakeAt !== void 0) return;
6141
+ return `running session cannot transition to ${nextState.phase}`;
6142
+ }
6143
+ if (previous.phase === "stopping") {
6144
+ if (nextState.phase === "stopped" && nextState.lease === void 0 && nextState.cancellation !== void 0) return;
6145
+ if (nextState.phase === "reconciliation-required" && nextState.lease === void 0) return void 0;
6146
+ return `stopping session cannot transition to ${nextState.phase}`;
6147
+ }
6148
+ if (previous.phase === "queued") {
6149
+ if (nextState.phase === "running" && nextState.lease !== void 0) return void 0;
6150
+ if (nextState.phase === "queued" && nextState.lease === void 0 && nextState.wakeAt === previous.wakeAt) return;
6151
+ if (nextState.phase === "stopped" && nextState.lease === void 0) return void 0;
6152
+ if (nextState.phase === "reconciliation-required" && nextState.lease === void 0) return void 0;
6153
+ return `queued session cannot transition to ${nextState.phase}`;
6154
+ }
6155
+ if (previous.phase === "waiting") {
6156
+ if (nextState.phase === "running" && nextState.lease !== void 0) return void 0;
6157
+ if (nextState.phase === "waiting" && nextState.lease === void 0 && nextState.wakeAt === previous.wakeAt) return;
6158
+ if (nextState.phase === "queued" && nextState.wakeAt !== void 0) return void 0;
6159
+ if (nextState.phase === "stopped" && nextState.lease === void 0) return void 0;
6160
+ if (nextState.phase === "reconciliation-required" && nextState.lease === void 0) return void 0;
6161
+ return `waiting session cannot transition to ${nextState.phase}`;
6162
+ }
6163
+ if (previous.phase === "input-required") {
6164
+ if (nextState.phase === "input-required" && nextState.lease === void 0) return void 0;
6165
+ if (nextState.phase === "queued" && nextState.wakeAt !== void 0) return void 0;
6166
+ if (nextState.phase === "stopped" && nextState.lease === void 0) return void 0;
6167
+ if (nextState.phase === "reconciliation-required" && nextState.lease === void 0) return void 0;
6168
+ return `input-required session cannot transition to ${nextState.phase}`;
6169
+ }
6170
+ if (isBackgroundSessionTerminalPhase(previous.phase)) {
6171
+ if (previous.phase === "reconciliation-required") {
6172
+ if (nextState.phase !== "queued" && nextState.phase !== "stopped") return "reconciliation-required session can only continue or stop";
6173
+ return;
6174
+ }
6175
+ return `terminal ${previous.phase} session cannot transition`;
6176
+ }
6177
+ }
6178
+ function holdsSameLease(previous, nextState) {
6179
+ return nextState.lease !== void 0 && previous.lease !== void 0 && nextState.lease.owner === previous.lease.owner && nextState.lease.epoch === previous.lease.epoch;
6180
+ }
6181
+ //#endregion
6182
+ //#region src/application/background-session/background-session-service.ts
6183
+ var BackgroundSessionCallerDenied = class extends Error {
6184
+ name = "BackgroundSessionCallerDenied";
6185
+ constructor(message) {
6186
+ super(message);
6187
+ }
6188
+ };
6189
+ function createBackgroundSessionService(options) {
6190
+ const serial = createSerialExecutor();
6191
+ const start = async (input) => {
6192
+ const now = options.clock.now();
6193
+ const origin = requireOrigin(input.context);
6194
+ const state = createBackgroundSession({
6195
+ authority: input.authority,
6196
+ displayName: input.displayName?.trim() || input.sessionId,
6197
+ now,
6198
+ origin: {
6199
+ allowedActorOpenIds: origin.allowedActorOpenIds,
6200
+ ...origin.conversationId === void 0 ? {} : { conversationId: origin.conversationId },
6201
+ endpointId: origin.endpointId,
6202
+ ...input.context.memory ? { memory: {
6203
+ audience: input.context.memory.audience,
6204
+ ...input.context.memory.conversationId ? { conversationId: input.context.memory.conversationId } : {},
6205
+ ...input.context.memory.projectId ? { projectId: input.context.memory.projectId } : {},
6206
+ subjectId: input.context.memory.subjectId,
6207
+ tenantId: input.context.memory.tenantId
6208
+ } } : {},
6209
+ tenantKey: origin.tenantKey
6210
+ },
6211
+ parentRunId: input.context.runId,
6212
+ prompt: input.prompt,
6213
+ sessionId: input.sessionId,
6214
+ sourceMessageId: requireSourceMessageId(input.context)
6215
+ });
6216
+ return toSummary(await options.repository.create(state));
6217
+ };
6218
+ const wait = async (input) => {
6219
+ const sessionId = sessionIdFromSessionKey(input.context.sessionKey);
6220
+ if (!sessionId) throw new BackgroundSessionCallerDenied("background.wait is only available inside a background session step");
6221
+ if (input.delayMs !== void 0 && input.until !== void 0) throw new BackgroundSessionCallerDenied("background.wait cannot combine delayMs and until");
6222
+ const now = options.clock.now();
6223
+ let wakeAt;
6224
+ if (input.delayMs !== void 0) {
6225
+ if (!Number.isSafeInteger(input.delayMs) || input.delayMs < 1) throw new BackgroundSessionCallerDenied("background.wait delayMs must be a positive integer");
6226
+ wakeAt = new Date(Date.parse(now) + input.delayMs).toISOString();
6227
+ } else if (input.until !== void 0) {
6228
+ const parsed = Date.parse(input.until);
6229
+ if (!Number.isFinite(parsed)) throw new BackgroundSessionCallerDenied("background.wait until must be an ISO 8601 timestamp");
6230
+ wakeAt = new Date(parsed).toISOString();
6231
+ }
6232
+ return toSummary(requireState(await serial.run(async () => {
6233
+ const state = await options.repository.get(sessionId);
6234
+ if (!state) throw new BackgroundSessionCallerDenied(`background session not found: ${sessionId}`);
6235
+ requireMatchingOrigin(state, input.context);
6236
+ const nextState = suspendBackgroundSession(state, {
6237
+ now,
6238
+ ...input.reason === void 0 ? {} : { reason: input.reason },
6239
+ ...wakeAt ? { wakeAt } : {}
6240
+ });
6241
+ return options.repository.update({
6242
+ build: () => nextState,
6243
+ expectedRevision: state.revision,
6244
+ sessionId
6245
+ });
6246
+ }), sessionId));
6247
+ };
6248
+ const list = async (input) => {
6249
+ return (await options.repository.list(input.phase === void 0 ? void 0 : { phase: input.phase })).filter((state) => matchesOrigin(state, input.context)).sort((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, input.limit).map(toSummary);
6250
+ };
6251
+ const status = async (input) => {
6252
+ return toDetail(await requireOwnedState(input.sessionId, input.context));
6253
+ };
6254
+ const send = async (input) => {
6255
+ return toSummary(requireState(await serial.run(async () => {
6256
+ const state = await requireOwnedState(input.sessionId, input.context);
6257
+ const nextState = appendBackgroundSessionInput(state, {
6258
+ message: input.message,
6259
+ now: options.clock.now()
6260
+ });
6261
+ return options.repository.update({
6262
+ build: () => nextState,
6263
+ expectedRevision: state.revision,
6264
+ sessionId: input.sessionId
6265
+ });
6266
+ }), input.sessionId));
6267
+ };
6268
+ const stop = async (input) => {
6269
+ return toSummary(requireState(await serial.run(async () => {
6270
+ const state = await requireOwnedState(input.sessionId, input.context);
6271
+ const nextState = requestBackgroundSessionStop(state, {
6272
+ now: options.clock.now(),
6273
+ reason: input.reason ?? "stopped by conversation"
6274
+ });
6275
+ return updateAndEnqueueStopped(input.sessionId, state.revision, nextState);
6276
+ }), input.sessionId));
6277
+ };
6278
+ const requireOwnedState = async (sessionId, context) => {
6279
+ const state = await options.repository.get(sessionId);
6280
+ if (!state) throw new BackgroundSessionCallerDenied(`background session not found: ${sessionId}`);
6281
+ requireMatchingOrigin(state, context);
6282
+ return state;
6283
+ };
6284
+ const updateAndEnqueueStopped = async (sessionId, expectedRevision, nextState) => {
6285
+ const stored = await options.repository.update({
6286
+ build: () => nextState,
6287
+ expectedRevision,
6288
+ sessionId
6289
+ });
6290
+ if (stored?.phase === "stopped") await options.deliveries.enqueue({
6291
+ createdAt: options.clock.now(),
6292
+ deliveryId: terminalDeliveryId(sessionId, "stopped"),
6293
+ kind: "stopped",
6294
+ sessionId,
6295
+ text: stopNotice$1(stored)
6296
+ });
6297
+ return stored;
6298
+ };
6299
+ const resolveReconciliation = async (input) => {
6300
+ return toSummary(requireState(await serial.run(async () => {
6301
+ const state = await options.repository.get(input.sessionId);
6302
+ if (!state) throw new BackgroundSessionCallerDenied(`background session not found: ${input.sessionId}`);
6303
+ const nextState = resolveBackgroundSessionReconciliation(state, {
6304
+ now: options.clock.now(),
6305
+ outcome: input.outcome
6306
+ });
6307
+ return updateAndEnqueueStopped(input.sessionId, state.revision, nextState);
6308
+ }), input.sessionId));
6309
+ };
6310
+ return {
6311
+ list,
6312
+ resolveReconciliation,
6313
+ send,
6314
+ start,
6315
+ status,
6316
+ stop,
6317
+ wait
6318
+ };
6319
+ }
6320
+ function sessionIdFromSessionKey(sessionKey) {
6321
+ const prefix = `${createBackgroundSessionKey("")}`;
6322
+ return sessionKey.startsWith(prefix) ? sessionKey.slice(prefix.length) : void 0;
6323
+ }
6324
+ function terminalDeliveryId(sessionId, kind) {
6325
+ return `bg-final:${sessionId}:${kind}`;
6326
+ }
6327
+ function progressDeliveryId(sessionId, stepCount) {
6328
+ return `bg-progress:${sessionId}:${stepCount}`;
6329
+ }
6330
+ function requireOrigin(context) {
6331
+ if (!context.origin || !context.origin.endpointId || !context.origin.tenantKey) throw new BackgroundSessionCallerDenied("background tools require a trusted invocation origin; this run has none");
6332
+ return context.origin;
6333
+ }
6334
+ function requireSourceMessageId(context) {
6335
+ if (!context.sourceMessageId?.trim()) throw new BackgroundSessionCallerDenied("background.start requires a trusted source message id");
6336
+ return context.sourceMessageId;
6337
+ }
6338
+ function requireMatchingOrigin(state, context) {
6339
+ if (!matchesOrigin(state, context)) throw new BackgroundSessionCallerDenied("background session is not owned by this conversation");
6340
+ }
6341
+ function matchesOrigin(state, context) {
6342
+ const origin = context.origin;
6343
+ if (!origin) return false;
6344
+ if (context.agentId !== state.authority.agentId) return false;
6345
+ if (state.origin.endpointId !== origin.endpointId) return false;
6346
+ if (state.origin.tenantKey !== origin.tenantKey) return false;
6347
+ if ((state.origin.conversationId ?? void 0) !== (origin.conversationId ?? void 0)) return false;
6348
+ return true;
6349
+ }
6350
+ function requireState(state, sessionId) {
6351
+ if (!state) throw new BackgroundSessionCallerDenied(`background session not found: ${sessionId}`);
6352
+ return state;
6353
+ }
6354
+ function toSummary(state) {
6355
+ return {
6356
+ createdAt: state.createdAt,
6357
+ displayName: state.displayName,
6358
+ phase: state.phase,
6359
+ sessionId: state.sessionId,
6360
+ stepCount: state.stepCount,
6361
+ updatedAt: state.updatedAt,
6362
+ ...state.wakeAt ? { wakeAt: state.wakeAt } : {}
6363
+ };
6364
+ }
6365
+ function toDetail(state) {
6366
+ return {
6367
+ ...toSummary(state),
6368
+ ...state.cancellation ? { cancellationReason: state.cancellation.reason } : {},
6369
+ ...state.errorMessage ? { errorMessage: state.errorMessage } : {},
6370
+ parentRunId: state.parentRunId,
6371
+ pendingInput: state.pendingInput,
6372
+ ...state.reconciliationNote ? { reconciliationNote: state.reconciliationNote } : {},
6373
+ ...state.result ? { result: state.result } : {}
6374
+ };
6375
+ }
6376
+ function stopNotice$1(state) {
6377
+ return `后台会话「${state.displayName}」已停止。${state.cancellation ? `原因:${state.cancellation.reason}` : ""}`.trim();
6378
+ }
6379
+ //#endregion
6380
+ //#region src/application/background-session/background-session-repository.ts
6381
+ var BackgroundSessionRepositoryConflict = class extends Error {
6382
+ name = "BackgroundSessionRepositoryConflict";
6383
+ constructor(sessionId, message) {
6384
+ super(`${sessionId}: ${message}`);
6385
+ }
6386
+ };
6387
+ var BackgroundSessionRepositoryCorrupted = class extends Error {
6388
+ name = "BackgroundSessionRepositoryCorrupted";
6389
+ };
6390
+ function createBackgroundSessionRepository(options = {}) {
6391
+ const serial = createSerialExecutor();
6392
+ const states = /* @__PURE__ */ new Map();
6393
+ for (const state of options.initial ?? []) states.set(state.sessionId, structuredClone(state));
6394
+ const persist = async (state) => {
6395
+ if (options.persist) await options.persist(state);
6396
+ };
6397
+ return {
6398
+ create: (state) => serial.run(async () => {
6399
+ if (states.has(state.sessionId)) throw new BackgroundSessionRepositoryConflict(state.sessionId, "duplicate background session id");
6400
+ states.set(state.sessionId, structuredClone(state));
6401
+ await persist(state);
6402
+ return structuredClone(state);
6403
+ }),
6404
+ get: (sessionId) => serial.run(async () => {
6405
+ const state = states.get(sessionId);
6406
+ return state ? structuredClone(state) : void 0;
6407
+ }),
6408
+ list: (options) => serial.run(async () => {
6409
+ let results = [...states.values()];
6410
+ if (options?.phase !== void 0) results = results.filter((state) => state.phase === options.phase);
6411
+ results.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
6412
+ if (options?.limit !== void 0) results = results.slice(0, options.limit);
6413
+ return results.map((state) => structuredClone(state));
6414
+ }),
6415
+ update: (input) => serial.run(async () => {
6416
+ const previous = states.get(input.sessionId);
6417
+ if (!previous) return void 0;
6418
+ if (previous.revision !== input.expectedRevision) throw new BackgroundSessionRepositoryConflict(input.sessionId, `revision conflict: expected ${input.expectedRevision}, found ${previous.revision}`);
6419
+ if (input.expectedLease !== void 0) {
6420
+ const leaseMismatch = leaseConflict(input.sessionId, previous.lease, input.expectedLease, input.now);
6421
+ if (leaseMismatch) throw new BackgroundSessionRepositoryConflict(input.sessionId, leaseMismatch);
6422
+ }
6423
+ const nextState = input.build(previous);
6424
+ const invalid = isValidBackgroundSessionTransition(previous, nextState);
6425
+ if (invalid) throw new BackgroundSessionRepositoryConflict(input.sessionId, `invalid transition: ${invalid}`);
6426
+ states.set(input.sessionId, structuredClone(nextState));
6427
+ await persist(nextState);
6428
+ return structuredClone(nextState);
6429
+ })
6430
+ };
6431
+ }
6432
+ function leaseConflict(_sessionId, lease, expected, now) {
6433
+ if (expected.kind === "absent") {
6434
+ if (lease !== void 0) return `lease conflict: expected no lease, found owner ${lease.owner} epoch ${lease.epoch}`;
6435
+ return;
6436
+ }
6437
+ if (expected.kind === "absent-or-stale") {
6438
+ if (lease !== void 0 && !isExpired(lease, now)) return `lease conflict: expected absent or stale lease, found live lease owner ${lease.owner} epoch ${lease.epoch}`;
6439
+ return;
6440
+ }
6441
+ if (lease === void 0 || lease.owner !== expected.owner || lease.epoch !== expected.epoch) return `lease conflict: expected owner ${expected.owner} epoch ${expected.epoch}`;
6442
+ }
6443
+ function isExpired(lease, now) {
6444
+ return lease !== void 0 && lease.expiresAt <= (now ?? (/* @__PURE__ */ new Date()).toISOString());
6445
+ }
6446
+ //#endregion
6447
+ //#region src/application/background-session/background-session-delivery-store.ts
6448
+ var BackgroundSessionDeliveryConflict = class extends Error {
6449
+ name = "BackgroundSessionDeliveryConflict";
6450
+ constructor(deliveryId, message) {
6451
+ super(`${deliveryId}: ${message}`);
6452
+ }
6453
+ };
6454
+ function createBackgroundSessionDeliveryStore(options = {}) {
6455
+ const serial = createSerialExecutor();
6456
+ const records = /* @__PURE__ */ new Map();
6457
+ for (const record of options.initial ?? []) records.set(record.deliveryId, structuredClone(record));
6458
+ const persist = async (record) => {
6459
+ if (options.persist) await options.persist(record);
6460
+ };
6461
+ return {
6462
+ enqueue: (input) => serial.run(async () => {
6463
+ const existing = records.get(input.deliveryId);
6464
+ if (existing) return structuredClone(existing);
6465
+ const record = {
6466
+ createdAt: input.createdAt,
6467
+ deliveryId: input.deliveryId,
6468
+ kind: input.kind,
6469
+ revision: 1,
6470
+ sessionId: input.sessionId,
6471
+ state: "pending",
6472
+ text: input.text
6473
+ };
6474
+ records.set(input.deliveryId, structuredClone(record));
6475
+ await persist(record);
6476
+ return structuredClone(record);
6477
+ }),
6478
+ pending: () => serial.run(async () => {
6479
+ return [...records.values()].filter((record) => record.state === "pending").sort((left, right) => left.createdAt.localeCompare(right.createdAt)).map((record) => structuredClone(record));
6480
+ }),
6481
+ markDelivered: (deliveryId, providerMessageId) => serial.run(async () => {
6482
+ const previous = records.get(deliveryId);
6483
+ if (!previous) return void 0;
6484
+ if (previous.state !== "pending") return structuredClone(previous);
6485
+ const nextState = {
6486
+ ...previous,
6487
+ providerMessageId,
6488
+ revision: previous.revision + 1,
6489
+ state: "delivered"
6490
+ };
6491
+ records.set(deliveryId, structuredClone(nextState));
6492
+ await persist(nextState);
6493
+ return structuredClone(nextState);
6494
+ })
6495
+ };
6496
+ }
6497
+ //#endregion
6498
+ //#region src/application/background-session/background-session-supervisor.ts
6499
+ function createBackgroundSessionSupervisor(options) {
6500
+ const owner = `supervisor:${randomUUID()}`;
6501
+ const inFlight = /* @__PURE__ */ new Map();
6502
+ const stepControllers = /* @__PURE__ */ new Map();
6503
+ const counters = {
6504
+ completed: 0,
6505
+ deliveriesDelivered: 0,
6506
+ failed: 0,
6507
+ started: 0,
6508
+ staleLeaseEventsDropped: 0,
6509
+ stopped: 0
6510
+ };
6511
+ let repositoryHealthy = true;
6512
+ let snapshot = emptyPhaseCounts();
6513
+ let oldestDueAt;
6514
+ const requeuedInPass = /* @__PURE__ */ new Set();
6515
+ const refreshSnapshot = async () => {
6516
+ const counts = {
6517
+ completed: 0,
6518
+ failed: 0,
6519
+ "input-required": 0,
6520
+ queued: 0,
6521
+ "reconciliation-required": 0,
6522
+ running: 0,
6523
+ stopped: 0,
6524
+ stopping: 0,
6525
+ waiting: 0
6526
+ };
6527
+ let oldest;
6528
+ const now = options.clock.now();
6529
+ for (const session of await options.repository.list()) {
6530
+ counts[session.phase] += 1;
6531
+ if (isBackgroundSessionDue(session, now)) {
6532
+ const dueAt = session.wakeAt ?? session.createdAt;
6533
+ if (oldest === void 0 || dueAt < oldest) oldest = dueAt;
6534
+ }
6535
+ }
6536
+ snapshot = Object.freeze(counts);
6537
+ oldestDueAt = oldest;
6538
+ };
6539
+ const supervisionPass = async () => {
6540
+ try {
6541
+ await resolveStaleLeases();
6542
+ await expireLifetime();
6543
+ await stopStoppingSessions();
6544
+ await drainDeliveries();
6545
+ await startDueSessions();
6546
+ await refreshSnapshot();
6547
+ repositoryHealthy = true;
6548
+ } catch (error) {
6549
+ repositoryHealthy = false;
6550
+ throw error;
6551
+ }
6552
+ };
6553
+ const resolveStaleLeases = async () => {
6554
+ const now = options.clock.now();
6555
+ for (const session of await options.repository.list()) {
6556
+ if (session.lease === void 0 || inFlight.has(session.sessionId)) continue;
6557
+ if (!(session.lease.owner !== owner || isBackgroundSessionLeaseExpired(session, now))) continue;
6558
+ counters.staleLeaseEventsDropped += 1;
6559
+ const expectedLease = {
6560
+ kind: "held",
6561
+ owner: session.lease.owner,
6562
+ epoch: session.lease.epoch
6563
+ };
6564
+ if (session.phase === "running") {
6565
+ await options.repository.update({
6566
+ build: (state) => requeueInterruptedBackgroundSessionStep(state, {
6567
+ now,
6568
+ wakeText: interruptedStepWakeText(state)
6569
+ }),
6570
+ expectedLease,
6571
+ expectedRevision: session.revision,
6572
+ sessionId: session.sessionId
6573
+ });
6574
+ requeuedInPass.add(session.sessionId);
6575
+ continue;
6576
+ }
6577
+ if (session.phase === "stopping") {
6578
+ await completeStop(session, expectedLease);
6579
+ continue;
6580
+ }
6581
+ await options.repository.update({
6582
+ build: (state) => releaseBackgroundSessionLease(state),
6583
+ expectedLease,
6584
+ expectedRevision: session.revision,
6585
+ sessionId: session.sessionId
6586
+ });
6587
+ }
6588
+ };
6589
+ const expireLifetime = async () => {
6590
+ const now = options.clock.now();
6591
+ const cutoff = Date.parse(now) - options.config.sessionLifetimeMs;
6592
+ for (const session of await options.repository.list()) {
6593
+ if (isBackgroundSessionTerminalPhase(session.phase)) continue;
6594
+ if (Date.parse(session.createdAt) > cutoff) continue;
6595
+ const nextState = requestBackgroundSessionStop(session, {
6596
+ now,
6597
+ reason: "background session lifetime exceeded"
6598
+ });
6599
+ const stored = await options.repository.update({
6600
+ build: () => nextState,
6601
+ expectedRevision: session.revision,
6602
+ sessionId: session.sessionId
6603
+ });
6604
+ if (stored?.phase === "stopped") {
6605
+ counters.stopped += 1;
6606
+ await enqueueDelivery(stored.sessionId, "stopped", stopNotice(stored), stored);
6607
+ } else stepControllers.get(session.sessionId)?.abort(/* @__PURE__ */ new Error("background session lifetime exceeded"));
6608
+ }
6609
+ };
6610
+ const stopStoppingSessions = async () => {
6611
+ for (const session of await options.repository.list()) {
6612
+ if (session.phase !== "stopping") continue;
6613
+ if (inFlight.has(session.sessionId)) {
6614
+ stepControllers.get(session.sessionId)?.abort(/* @__PURE__ */ new Error("background session stop requested"));
6615
+ continue;
6616
+ }
6617
+ const expectedLease = session.lease ? {
6618
+ kind: "held",
6619
+ owner: session.lease.owner,
6620
+ epoch: session.lease.epoch
6621
+ } : { kind: "absent" };
6622
+ await completeStop(session, expectedLease);
6623
+ }
6624
+ };
6625
+ const completeStop = async (state, expectedLease) => {
6626
+ const stopped = await options.repository.update({
6627
+ build: (current) => completeBackgroundSessionStop(current, { now: options.clock.now() }),
6628
+ expectedLease,
6629
+ expectedRevision: state.revision,
6630
+ sessionId: state.sessionId
6631
+ });
6632
+ if (stopped) {
6633
+ counters.stopped += 1;
6634
+ await enqueueDelivery(stopped.sessionId, "stopped", stopNotice(stopped), stopped);
6635
+ }
6636
+ };
6637
+ const startDueSessions = async () => {
6638
+ const now = options.clock.now();
6639
+ for (const session of await options.repository.list()) {
6640
+ if (inFlight.size >= options.config.maxConcurrentSessions) break;
6641
+ if (inFlight.has(session.sessionId)) continue;
6642
+ if (!isBackgroundSessionDue(session, now)) continue;
6643
+ if (session.lease !== void 0 && !isBackgroundSessionLeaseExpired(session, now)) continue;
6644
+ const step = runStep(session).finally(() => {
6645
+ inFlight.delete(session.sessionId);
6646
+ });
6647
+ inFlight.set(session.sessionId, step);
6648
+ step.catch((error) => {
6649
+ options.onError?.(error);
6650
+ });
6651
+ }
6652
+ };
6653
+ const runStep = async (session) => {
6654
+ const now = options.clock.now();
6655
+ const stepCount = session.stepCount + 1;
6656
+ const wakeText = requeuedInPass.has(session.sessionId) ? interruptedStepWakeText(session) : buildWakeText(session);
6657
+ requeuedInPass.delete(session.sessionId);
6658
+ const lease = {
6659
+ epoch: (session.lease?.epoch ?? 0) + 1,
6660
+ expiresAt: toIso(Date.parse(now) + options.config.leaseMs),
6661
+ owner
6662
+ };
6663
+ const claimed = await options.repository.update({
6664
+ build: (state) => claimBackgroundSession(state, {
6665
+ lease,
6666
+ now,
6667
+ stepRunId: `bg-step:${session.sessionId}:${stepCount}`,
6668
+ wakeText
6669
+ }),
6670
+ expectedLease: { kind: "absent-or-stale" },
6671
+ expectedRevision: session.revision,
6672
+ now,
6673
+ sessionId: session.sessionId
6674
+ });
6675
+ if (!claimed) return;
6676
+ counters.started += 1;
6677
+ const controller = new AbortController();
6678
+ stepControllers.set(session.sessionId, controller);
6679
+ let outcome;
6680
+ try {
6681
+ let settled = false;
6682
+ const renewal = (async () => {
6683
+ while (!settled) {
6684
+ await Effect.runPromise(options.sleep(options.config.leaseRenewalIntervalMs)).catch(() => void 0);
6685
+ if (settled) break;
6686
+ try {
6687
+ const current = await options.repository.get(session.sessionId);
6688
+ if (!current || current.lease === void 0 || current.lease.owner !== owner || current.lease.epoch !== lease.epoch) {
6689
+ controller.abort(/* @__PURE__ */ new Error("background session lease was lost"));
6690
+ break;
6691
+ }
6692
+ if (!await options.repository.update({
6693
+ build: (state) => renewBackgroundSessionLease(state, {
6694
+ expiresAt: toIso(Date.parse(options.clock.now()) + options.config.leaseMs),
6695
+ epoch: lease.epoch,
6696
+ owner
6697
+ }),
6698
+ expectedLease: {
6699
+ kind: "held",
6700
+ owner,
6701
+ epoch: lease.epoch
6702
+ },
6703
+ expectedRevision: current.revision,
6704
+ sessionId: session.sessionId
6705
+ })) controller.abort(/* @__PURE__ */ new Error("background session lease renewal was denied"));
6706
+ } catch {
6707
+ controller.abort(/* @__PURE__ */ new Error("background session lease renewal failed"));
6708
+ }
6709
+ }
6710
+ })();
6711
+ outcome = await options.runStep({
6712
+ session: claimed,
6713
+ signal: controller.signal,
6714
+ wakeText
6715
+ }).then((result) => ({
6716
+ ok: true,
6717
+ result
6718
+ }), (error) => ({
6719
+ error,
6720
+ ok: false
6721
+ }));
6722
+ settled = true;
6723
+ renewal.catch(() => void 0);
6724
+ } finally {
6725
+ stepControllers.delete(session.sessionId);
6726
+ }
6727
+ try {
6728
+ await commitStep(claimed, outcome, lease);
6729
+ } catch (error) {
6730
+ options.onError?.(error);
6731
+ await requeueAfterFailedCommit(session.sessionId, lease, error);
6732
+ }
6733
+ };
6734
+ const requeueAfterFailedCommit = async (sessionId, lease, error) => {
6735
+ try {
6736
+ const current = await options.repository.get(sessionId);
6737
+ if (!current || current.phase !== "running") return;
6738
+ await options.repository.update({
6739
+ build: (state) => requeueInterruptedBackgroundSessionStep(state, {
6740
+ now: options.clock.now(),
6741
+ wakeText: `步骤结果提交失败(${errorMessageOf(error)}),将重试`
6742
+ }),
6743
+ expectedLease: {
6744
+ kind: "held",
6745
+ owner: lease.owner,
6746
+ epoch: lease.epoch
6747
+ },
6748
+ expectedRevision: current.revision,
6749
+ sessionId
6750
+ });
6751
+ } catch (commitError) {
6752
+ options.onError?.(commitError);
6753
+ }
6754
+ };
6755
+ const commitStep = async (claimed, outcome, lease) => {
6756
+ const now = options.clock.now();
6757
+ const current = await options.repository.get(claimed.sessionId);
6758
+ if (!current) return;
6759
+ const expectedLease = {
6760
+ kind: "held",
6761
+ owner: lease.owner,
6762
+ epoch: lease.epoch
6763
+ };
6764
+ if (current.phase === "waiting" || current.phase === "input-required") {
6765
+ const text = outcome.ok ? outcome.result.finalText : "";
6766
+ await options.repository.update({
6767
+ build: (state) => releaseBackgroundSessionLease(state),
6768
+ expectedLease,
6769
+ expectedRevision: current.revision,
6770
+ sessionId: current.sessionId
6771
+ });
6772
+ if (text.trim() !== "") await enqueueDelivery(current.sessionId, "progress", text, current);
6773
+ return;
6774
+ }
6775
+ if (current.phase === "stopping") {
6776
+ await completeStop(current, expectedLease);
6777
+ return;
6778
+ }
6779
+ if (current.phase !== "running") return;
6780
+ if (outcome.ok) {
6781
+ const completed = await options.repository.update({
6782
+ build: (state) => completeBackgroundSessionStep(state, {
6783
+ now,
6784
+ stepRunId: outcome.result.runId,
6785
+ text: outcome.result.finalText
6786
+ }),
6787
+ expectedLease,
6788
+ expectedRevision: current.revision,
6789
+ sessionId: current.sessionId
6790
+ });
6791
+ if (completed) {
6792
+ counters.completed += 1;
6793
+ await enqueueDelivery(completed.sessionId, "final", completed.result?.text ?? "", completed);
6794
+ }
6795
+ return;
6796
+ }
6797
+ const errorMessage = errorMessageOf(outcome.error);
6798
+ if (isFencedOperationError(outcome.error)) {
6799
+ const parked = await options.repository.update({
6800
+ build: (state) => parkBackgroundSessionForReconciliation(state, {
6801
+ now,
6802
+ reason: `step failed on a fenced operation: ${errorMessage}`
6803
+ }),
6804
+ expectedLease,
6805
+ expectedRevision: current.revision,
6806
+ sessionId: current.sessionId
6807
+ });
6808
+ if (parked) await enqueueDelivery(parked.sessionId, "reconciliation", `后台会话「${parked.displayName}」需要人工对账:${parked.reconciliationNote ?? errorMessage}`, parked);
6809
+ return;
6810
+ }
6811
+ if (isRetryableStepError(outcome.error) && current.consecutiveFailures + 1 < options.config.maxConsecutiveFailures) {
6812
+ const backoff = options.config.retryBackoffMs * 2 ** current.consecutiveFailures;
6813
+ await options.repository.update({
6814
+ build: (state) => failBackgroundSessionStep(state, {
6815
+ errorMessage,
6816
+ now,
6817
+ retryable: true,
6818
+ wakeAt: toIso(Date.parse(now) + backoff)
6819
+ }),
6820
+ expectedLease,
6821
+ expectedRevision: current.revision,
6822
+ sessionId: current.sessionId
6823
+ });
6824
+ return;
6825
+ }
6826
+ const failed = await options.repository.update({
6827
+ build: (state) => failBackgroundSessionStep(state, {
6828
+ errorMessage,
6829
+ now,
6830
+ retryable: false
6831
+ }),
6832
+ expectedLease,
6833
+ expectedRevision: current.revision,
6834
+ sessionId: current.sessionId
6835
+ });
6836
+ if (failed) {
6837
+ counters.failed += 1;
6838
+ await enqueueDelivery(failed.sessionId, "failed", `后台会话「${failed.displayName}」失败:${failed.errorMessage ?? errorMessage}`, failed);
6839
+ }
6840
+ };
6841
+ const drainDeliveries = async () => {
6842
+ const pending = await options.deliveries.pending();
6843
+ for (const record of pending) try {
6844
+ const { providerMessageId } = await options.deliver(record);
6845
+ if (await options.deliveries.markDelivered(record.deliveryId, providerMessageId)) counters.deliveriesDelivered += 1;
6846
+ } catch (error) {
6847
+ options.onError?.(error);
6848
+ }
6849
+ };
6850
+ const enqueueDelivery = async (sessionId, kind, text, session) => {
6851
+ if (text.trim() === "") return;
6852
+ const deliveryId = kind === "progress" ? progressDeliveryId(sessionId, session.stepCount) : terminalDeliveryId(sessionId, kind);
6853
+ await options.deliveries.enqueue({
6854
+ createdAt: options.clock.now(),
6855
+ deliveryId,
6856
+ kind,
6857
+ sessionId,
6858
+ text
6859
+ });
6860
+ };
6861
+ const buildWakeText = (session) => {
6862
+ if (session.wakeCount === 0) return `你在一个后台会话中开始工作。任务:\n${session.prompt}\n\n继续工作直到给出最终结果;如果必须等待外部变化或用户输入,调用 background.wait。`;
6863
+ const parts = [`后台会话第 ${session.stepCount + 1} 步。任务:\n${session.prompt}`, "继续先前的工作(历史在会话记录中)。"];
6864
+ if (session.pendingInput.length > 0) parts.push(`用户新的输入:\n${session.pendingInput.join("\n---\n")}`);
6865
+ parts.push("完成后给出最终结果;需要等待时调用 background.wait。");
6866
+ return parts.join("\n\n");
6867
+ };
6868
+ const interruptedStepWakeText = (session) => `你的上一步在后台会话中被守护进程重启打断,未产生确定的工具副作用(副作用由工具账本保护)。继续先前的工作(历史在会话记录中)。` + (session.pendingInput.length > 0 ? `\n\n用户新的输入:\n${session.pendingInput.join("\n---\n")}` : "");
6869
+ const tick = () => Effect.promise(() => supervisionPass());
6870
+ const loop = createPeriodicEffectLoop({
6871
+ intervalMs: options.config.intervalMs,
6872
+ onError: (error) => {
6873
+ options.onError?.(error);
6874
+ },
6875
+ run: tick,
6876
+ sleep: options.sleep
6877
+ });
6878
+ const statusOf = () => Object.freeze({
6879
+ capacity: options.config.maxConcurrentSessions,
6880
+ counters: Object.freeze({ ...counters }),
6881
+ inFlightSteps: inFlight.size,
6882
+ ...oldestDueAt === void 0 ? {} : { oldestDueAt },
6883
+ owner,
6884
+ phaseCounts: snapshot,
6885
+ reconciliationCount: snapshot["reconciliation-required"],
6886
+ repositoryHealthy,
6887
+ running: loop.running()
6888
+ });
6889
+ return {
6890
+ recover: tick,
6891
+ start: () => Effect.sync(() => loop.start()),
6892
+ status: statusOf,
6893
+ stop: () => Effect.promise(async () => {
6894
+ for (const controller of stepControllers.values()) controller.abort(/* @__PURE__ */ new Error("background session supervisor is stopping"));
6895
+ await Promise.allSettled(inFlight.values());
6896
+ await loop.stop();
6897
+ }),
6898
+ tick
6899
+ };
6900
+ }
6901
+ function isFencedOperationError(error) {
6902
+ const message = errorMessageOf(error).toLowerCase();
6903
+ return message.includes("fenced") || message.includes("reconciliation-required");
6904
+ }
6905
+ function isRetryableStepError(error) {
6906
+ if (!(error instanceof Error)) return false;
6907
+ if (error.name === "AgentRunCancelled") return true;
6908
+ if (error.name === "AgentHarnessBusy" || error.name === "AgentInstanceBusy") return true;
6909
+ return false;
6910
+ }
6911
+ function errorMessageOf(error) {
6912
+ return error instanceof Error ? error.message : String(error);
6913
+ }
6914
+ function toIso(timeMs) {
6915
+ return new Date(timeMs).toISOString();
6916
+ }
6917
+ function stopNotice(session) {
6918
+ return `后台会话「${session.displayName}」已停止。${session.cancellation ? `原因:${session.cancellation.reason}` : ""}`.trim();
6919
+ }
6920
+ function emptyPhaseCounts() {
6921
+ return Object.freeze({
6922
+ completed: 0,
6923
+ failed: 0,
6924
+ "input-required": 0,
6925
+ queued: 0,
6926
+ "reconciliation-required": 0,
6927
+ running: 0,
6928
+ stopped: 0,
6929
+ stopping: 0,
6930
+ waiting: 0
6931
+ });
6932
+ }
6933
+ //#endregion
6934
+ //#region src/application/background-session/background-session-tools.ts
6935
+ function createBackgroundSessionHostTools(options) {
6936
+ const contracts = createBackgroundSessionToolContracts();
6937
+ const executors = new Map(contracts.map((contract) => [contract.id, createExecutor(contract, options)]));
6938
+ return contracts.map((contract) => Object.freeze({
6939
+ ...contract,
6940
+ createExecutor: () => ({ execute: (input, context) => asToolInputRejection$1(() => executors.get(contract.id)(input, context)) }),
6941
+ replayCompleted: (input, completedResult, context) => asToolInputRejection$1(() => replayCompleted(contract.id, input, completedResult, context, options))
6942
+ }));
6943
+ }
6944
+ function createExecutor(contract, options) {
6945
+ switch (contract.id) {
6946
+ case "background.start": return (input, context) => {
6947
+ const { prompt, displayName } = readObject(input, ["prompt", "displayName"]);
6948
+ if (typeof prompt !== "string" || prompt.trim() === "") throw new BackgroundSessionCallerDenied("background.start requires a non-empty prompt");
6949
+ if (displayName !== void 0 && typeof displayName !== "string") throw new BackgroundSessionCallerDenied("background.start displayName must be a string");
6950
+ const sessionId = options.createSessionId();
6951
+ return options.service.start({
6952
+ authority: buildAuthority(options.definition, context, sessionId),
6953
+ context,
6954
+ sessionId,
6955
+ ...displayName === void 0 ? {} : { displayName },
6956
+ prompt
6957
+ });
6958
+ };
6959
+ case "background.wait": return (input, context) => {
6960
+ const { delayMs, reason, until } = readWaitInput(input);
6961
+ return options.service.wait({
6962
+ context,
6963
+ ...delayMs === void 0 ? {} : { delayMs },
6964
+ ...reason === void 0 ? {} : { reason },
6965
+ ...until === void 0 ? {} : { until }
6966
+ });
6967
+ };
6968
+ case "background.list": return async (input, context) => {
6969
+ const { limit, phase } = readObject(input, ["limit", "phase"]);
6970
+ return { sessions: await options.service.list({
6971
+ context,
6972
+ ...limit === void 0 ? {} : { limit: readInteger(limit, "limit") },
6973
+ ...phase === void 0 ? {} : { phase: readPhase(phase) }
6974
+ }) };
6975
+ };
6976
+ case "background.status": return (input, context) => {
6977
+ const { sessionId } = readObject(input, ["sessionId"]);
6978
+ return options.service.status({
6979
+ context,
6980
+ sessionId: readString(sessionId, "sessionId")
6981
+ });
6982
+ };
6983
+ case "background.send": return (input, context) => {
6984
+ const { message, sessionId } = readObject(input, ["message", "sessionId"]);
6985
+ return options.service.send({
6986
+ context,
6987
+ message: readString(message, "message"),
6988
+ sessionId: readString(sessionId, "sessionId")
6989
+ });
6990
+ };
6991
+ case "background.stop": return (input, context) => {
6992
+ const { reason, sessionId } = readObject(input, ["reason", "sessionId"]);
6993
+ return options.service.stop({
6994
+ context,
6995
+ ...reason === void 0 ? {} : { reason: readString(reason, "reason") },
6996
+ sessionId: readString(sessionId, "sessionId")
6997
+ });
6998
+ };
6999
+ default: throw new BackgroundSessionCallerDenied(`unknown background tool: ${contract.id}`);
7000
+ }
7001
+ }
7002
+ function replayCompleted(toolId, input, completedResult, context, options) {
7003
+ switch (toolId) {
7004
+ case "background.start": {
7005
+ const sessionId = readReplayedSessionId(completedResult);
7006
+ return options.service.status({
7007
+ context,
7008
+ sessionId
7009
+ });
7010
+ }
7011
+ case "background.wait": return completedResult;
7012
+ case "background.list": return completedResult;
7013
+ case "background.status": {
7014
+ const sessionId = readReplayedSessionId(input);
7015
+ return options.service.status({
7016
+ context,
7017
+ sessionId
7018
+ });
7019
+ }
7020
+ case "background.send": {
7021
+ const sessionId = readReplayedSessionId(input);
7022
+ return options.service.status({
7023
+ context,
7024
+ sessionId
7025
+ });
7026
+ }
7027
+ case "background.stop": {
7028
+ const sessionId = readReplayedSessionId(input);
7029
+ return options.service.status({
7030
+ context,
7031
+ sessionId
7032
+ });
7033
+ }
7034
+ default: return completedResult;
7035
+ }
7036
+ }
7037
+ function buildAuthority(definition, context, sessionId) {
7038
+ return Object.freeze({
7039
+ agentId: definition.agentId,
7040
+ memoryScopes: definition.memory.scopes,
7041
+ policyEpoch: context.policyEpoch,
7042
+ profileRevision: definition.profileRevision,
7043
+ ...definition.projectSpaceId === void 0 ? {} : { projectSpaceId: definition.projectSpaceId },
7044
+ sessionKey: createBackgroundSessionKey(sessionId),
7045
+ toolGrantRevision: definition.toolGrantSet.revision
7046
+ });
7047
+ }
7048
+ function readObject(input, allowed) {
7049
+ return readBackgroundSessionObject(input, allowed, (message) => new BackgroundSessionCallerDenied(message));
7050
+ }
7051
+ function readString(value, name) {
7052
+ return readBackgroundSessionString(value, name, (message) => new BackgroundSessionCallerDenied(message));
7053
+ }
7054
+ function readInteger(value, name) {
7055
+ return readBackgroundSessionInteger(value, name, (message) => new BackgroundSessionCallerDenied(message));
7056
+ }
7057
+ function readPhase(value) {
7058
+ return readBackgroundSessionPhase(value, (message) => new BackgroundSessionCallerDenied(message));
7059
+ }
7060
+ function readReplayedSessionId(value) {
7061
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new BackgroundSessionCallerDenied("replayed background tool result is invalid");
7062
+ return readString(value.sessionId, "sessionId");
7063
+ }
7064
+ function readWaitInput(input) {
7065
+ return readBackgroundSessionWaitInput(input, (message) => new BackgroundSessionCallerDenied(message));
7066
+ }
7067
+ async function asToolInputRejection$1(operation) {
7068
+ try {
7069
+ return await operation();
7070
+ } catch (error) {
7071
+ if (error instanceof BackgroundSessionCallerDenied || error instanceof BackgroundSessionTransitionDenied) throw new RivusToolInputRejected(error.message);
7072
+ throw error;
7073
+ }
7074
+ }
7075
+ //#endregion
7076
+ //#region src/infrastructure/persistence/jsonl-snapshot-store.ts
7077
+ var JsonlSnapshotStoreCorrupted = class extends Error {
7078
+ name = "JsonlSnapshotStoreCorrupted";
7079
+ };
7080
+ async function loadJsonlSnapshotStore(options) {
7081
+ const raw = await readPersistenceFile(options.filePath);
7082
+ if (raw === void 0) return [];
7083
+ const lines = raw.split("\n");
7084
+ const latest = /* @__PURE__ */ new Map();
7085
+ let lineCount = 0;
7086
+ for (let index = 0; index < lines.length; index += 1) {
7087
+ const line = lines[index] ?? "";
7088
+ if (!line.trim()) continue;
7089
+ lineCount += 1;
7090
+ let parsed;
7091
+ try {
7092
+ parsed = JSON.parse(line);
7093
+ } catch {
7094
+ if (index === lines.length - 1) {
7095
+ await truncateAtLine(options.filePath, lines, index);
7096
+ break;
7097
+ }
7098
+ throw new JsonlSnapshotStoreCorrupted(`${options.errorLabel} JSONL at line ${index + 1} is not valid JSON`);
7099
+ }
7100
+ if (!isRecord$4(parsed) || parsed.version !== options.version) throw new JsonlSnapshotStoreCorrupted(`unsupported ${options.errorLabel} version at line ${index + 1}`);
7101
+ if (isRecord$4(parsed.snapshot)) {
7102
+ if (!Array.isArray(parsed.snapshot.records)) throw new JsonlSnapshotStoreCorrupted(`invalid ${options.errorLabel} snapshot at line ${index + 1}`);
7103
+ latest.clear();
7104
+ for (const value of parsed.snapshot.records) {
7105
+ if (!options.isRecord(value)) throw new JsonlSnapshotStoreCorrupted(`invalid ${options.errorLabel} snapshot at line ${index + 1}`);
7106
+ latest.set(options.keyOf(value), structuredClone(value));
7107
+ }
7108
+ continue;
7109
+ }
7110
+ if (!options.isRecord(parsed.record)) throw new JsonlSnapshotStoreCorrupted(`invalid ${options.errorLabel} record at line ${index + 1}`);
7111
+ const record = parsed.record;
7112
+ const previous = latest.get(options.keyOf(record));
7113
+ const invalid = options.validateSequence(previous, record, index + 1);
7114
+ if (invalid) throw new JsonlSnapshotStoreCorrupted(`invalid ${options.errorLabel} ${invalid} at line ${index + 1}`);
7115
+ latest.set(options.keyOf(record), structuredClone(record));
7116
+ }
7117
+ if (lineCount >= options.compactThreshold) await writeJsonlSnapshot(options.filePath, options.version, [...latest.values()]);
7118
+ return [...latest.values()];
7119
+ }
7120
+ async function appendJsonlRecord(filePath, version, record) {
7121
+ await mkdir(dirname(filePath), { recursive: true });
7122
+ await appendFile(filePath, `${JSON.stringify({
7123
+ record,
7124
+ version
7125
+ })}\n`, "utf8");
7126
+ }
7127
+ async function writeJsonlSnapshot(filePath, version, records) {
7128
+ await mkdir(dirname(filePath), { recursive: true });
7129
+ await writeFile(filePath, `${JSON.stringify({
7130
+ snapshot: { records },
7131
+ version
7132
+ })}\n`, "utf8");
7133
+ }
7134
+ async function truncateAtLine(filePath, lines, lineIndex) {
7135
+ let offset = 0;
7136
+ for (let index = 0; index < lineIndex; index += 1) offset += (lines[index] ?? "").length + 1;
7137
+ await truncate(filePath, offset);
7138
+ }
7139
+ //#endregion
7140
+ //#region src/infrastructure/persistence/jsonl-background-session-repository.ts
7141
+ const BACKGROUND_SESSION_JSONL_VERSION = 1;
7142
+ async function openJsonlBackgroundSessionRepository(options) {
7143
+ return createBackgroundSessionRepository({
7144
+ initial: await loadJsonlSnapshotStore({
7145
+ compactThreshold: options.compactThreshold ?? 5e3,
7146
+ errorLabel: "background session",
7147
+ filePath: options.filePath,
7148
+ isRecord: isBackgroundSessionState,
7149
+ keyOf: (record) => record.sessionId,
7150
+ validateSequence: validateSessionSequence,
7151
+ version: 1
7152
+ }),
7153
+ persist: (record) => appendJsonlRecord(options.filePath, 1, record)
7154
+ });
7155
+ }
7156
+ function validateSessionSequence(previous, record, _lineNumber) {
7157
+ if (previous === void 0) {
7158
+ if (record.revision !== 1 || record.phase !== "queued") return "first record";
7159
+ return;
7160
+ }
7161
+ if (record.revision !== previous.revision + 1) return "revision";
7162
+ return isValidBackgroundSessionTransition(previous, record);
7163
+ }
7164
+ function isBackgroundSessionState(value) {
7165
+ if (!isRecord$4(value)) return false;
7166
+ const phases = [
7167
+ "queued",
7168
+ "running",
7169
+ "waiting",
7170
+ "input-required",
7171
+ "stopping",
7172
+ "stopped",
7173
+ "completed",
7174
+ "failed",
7175
+ "reconciliation-required"
7176
+ ];
7177
+ if (typeof value.sessionId !== "string" || value.sessionId.trim() === "") return false;
7178
+ if (typeof value.displayName !== "string") return false;
7179
+ if (!phases.includes(value.phase)) return false;
7180
+ if (!Number.isInteger(value.revision) || value.revision < 1) return false;
7181
+ if (typeof value.parentRunId !== "string" || value.parentRunId.trim() === "") return false;
7182
+ if (typeof value.sourceMessageId !== "string" || value.sourceMessageId.trim() === "") return false;
7183
+ if (!isRecord$4(value.origin)) return false;
7184
+ const origin = value.origin;
7185
+ if (typeof origin.endpointId !== "string" || origin.endpointId.trim() === "") return false;
7186
+ if (typeof origin.tenantKey !== "string") return false;
7187
+ if (!Array.isArray(origin.allowedActorOpenIds) || origin.allowedActorOpenIds.some((id) => typeof id !== "string")) return false;
7188
+ if (origin.conversationId !== void 0 && typeof origin.conversationId !== "string") return false;
7189
+ if (origin.memory !== void 0 && !isRecord$4(origin.memory)) return false;
7190
+ if (!isRecord$4(value.authority)) return false;
7191
+ const authority = value.authority;
7192
+ if (typeof authority.agentId !== "string" || authority.agentId.trim() === "") return false;
7193
+ if (typeof authority.profileRevision !== "string" || authority.profileRevision.trim() === "") return false;
7194
+ if (typeof authority.toolGrantRevision !== "string" || authority.toolGrantRevision.trim() === "") return false;
7195
+ if (!Number.isInteger(authority.policyEpoch) || authority.policyEpoch < 0) return false;
7196
+ if (!Array.isArray(authority.memoryScopes) || authority.memoryScopes.some((scope) => typeof scope !== "string")) return false;
7197
+ if (typeof authority.sessionKey !== "string" || authority.sessionKey.trim() === "") return false;
7198
+ if (authority.projectSpaceId !== void 0 && typeof authority.projectSpaceId !== "string") return false;
7199
+ if (typeof value.prompt !== "string") return false;
7200
+ if (!Number.isInteger(value.stepCount) || value.stepCount < 0) return false;
7201
+ if (!Number.isInteger(value.wakeCount) || value.wakeCount < 0) return false;
7202
+ if (!Number.isInteger(value.consecutiveFailures) || value.consecutiveFailures < 0) return false;
7203
+ if (!Array.isArray(value.pendingInput) || value.pendingInput.some((entry) => typeof entry !== "string")) return false;
7204
+ if (value.currentStepRunId !== void 0 && typeof value.currentStepRunId !== "string") return false;
7205
+ if (value.lastWakeText !== void 0 && typeof value.lastWakeText !== "string") return false;
7206
+ if (value.wakeAt !== void 0 && typeof value.wakeAt !== "string") return false;
7207
+ if (value.errorMessage !== void 0 && typeof value.errorMessage !== "string") return false;
7208
+ if (value.reconciliationNote !== void 0 && typeof value.reconciliationNote !== "string") return false;
7209
+ if (typeof value.createdAt !== "string" || !isIso(value.createdAt)) return false;
7210
+ if (typeof value.updatedAt !== "string" || !isIso(value.updatedAt)) return false;
7211
+ if (value.lease !== void 0 && !isLease(value.lease)) return false;
7212
+ if (value.cancellation !== void 0) {
7213
+ if (!isRecord$4(value.cancellation)) return false;
7214
+ if (typeof value.cancellation.reason !== "string" || !isIso(value.cancellation.requestedAt)) return false;
7215
+ }
7216
+ if (value.result !== void 0) {
7217
+ if (!isRecord$4(value.result)) return false;
7218
+ if (typeof value.result.text !== "string" || typeof value.result.stepRunId !== "string" || !isIso(value.result.completedAt)) return false;
7219
+ }
7220
+ return true;
7221
+ }
7222
+ function isLease(value) {
7223
+ if (!isRecord$4(value)) return false;
7224
+ return typeof value.owner === "string" && value.owner.trim() !== "" && Number.isInteger(value.epoch) && value.epoch >= 0 && isIso(value.expiresAt);
7225
+ }
7226
+ function isIso(value) {
7227
+ return typeof value === "string" && Number.isFinite(Date.parse(value));
7228
+ }
7229
+ //#endregion
7230
+ //#region src/infrastructure/persistence/jsonl-background-session-delivery-store.ts
7231
+ const BACKGROUND_SESSION_DELIVERY_JSONL_VERSION = 1;
7232
+ async function openJsonlBackgroundSessionDeliveryStore(options) {
7233
+ return createBackgroundSessionDeliveryStore({
7234
+ initial: await loadJsonlSnapshotStore({
7235
+ compactThreshold: options.compactThreshold ?? 2e3,
7236
+ errorLabel: "background session delivery",
7237
+ filePath: options.filePath,
7238
+ isRecord: isDeliveryRecord,
7239
+ keyOf: (record) => record.deliveryId,
7240
+ validateSequence: validateDeliverySequence,
7241
+ version: 1
7242
+ }),
7243
+ persist: (record) => appendJsonlRecord(options.filePath, 1, record)
7244
+ });
7245
+ }
7246
+ function validateDeliverySequence(previous, record, _lineNumber) {
7247
+ if (previous === void 0) return record.revision === 1 && record.state === "pending" ? void 0 : "first record";
7248
+ if (record.revision !== previous.revision + 1) return "revision";
7249
+ return previous.state === "pending" && record.state === "delivered" ? void 0 : "transition";
7250
+ }
7251
+ function isDeliveryRecord(value) {
7252
+ if (!isRecord$4(value)) return false;
7253
+ if (typeof value.deliveryId !== "string" || value.deliveryId.trim() === "" || typeof value.sessionId !== "string" || value.sessionId.trim() === "") return false;
7254
+ if (typeof value.kind !== "string" || ![
7255
+ "progress",
7256
+ "final",
7257
+ "stopped",
7258
+ "failed",
7259
+ "reconciliation"
7260
+ ].includes(value.kind)) return false;
7261
+ if (typeof value.text !== "string") return false;
7262
+ if (value.state !== "pending" && value.state !== "delivered") return false;
7263
+ if (!Number.isInteger(value.revision) || value.revision < 1) return false;
7264
+ if (value.providerMessageId !== void 0 && typeof value.providerMessageId !== "string") return false;
7265
+ return typeof value.createdAt === "string" && Number.isFinite(Date.parse(value.createdAt));
7266
+ }
7267
+ //#endregion
7268
+ //#region src/infrastructure/feishu/feishu-interactive-card-send.ts
7269
+ function sendFeishuInteractiveCard(client, request, errorMessage) {
7270
+ return Effect.gen(function* () {
7271
+ const response = yield* client.request(request, errorMessage);
7272
+ const providerMessageId = readMessageId(response.body.data);
7273
+ if (!providerMessageId) return yield* Effect.fail(new FeishuOpenApiError(response.status, response.body.code, "Feishu send response missing message_id"));
7274
+ return Object.freeze({ providerMessageId });
7275
+ });
7276
+ }
7277
+ function readMessageId(data) {
7278
+ if (data === null || typeof data !== "object" || Array.isArray(data)) return void 0;
7279
+ const value = data.message_id;
7280
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
7281
+ }
7282
+ //#endregion
7283
+ //#region src/infrastructure/feishu/feishu-background-session-delivery.ts
7284
+ function createConfiguredFeishuBackgroundSessionDelivery(options) {
7285
+ const baseUrl = options.config.feishu.baseUrl.replace(/\/$/, "");
7286
+ return { deliver: (input) => Effect.runPromise(sendFeishuInteractiveCard(options.client, {
7287
+ body: {
7288
+ content: JSON.stringify(createBackgroundSessionCard(input)),
7289
+ msg_type: "interactive",
7290
+ receive_id: input.chatId,
7291
+ uuid: deliveryUuid$1(input.deliveryId)
7292
+ },
7293
+ method: "POST",
7294
+ url: `${baseUrl}/open-apis/im/v1/messages?receive_id_type=chat_id`
7295
+ }, "Feishu background session delivery failed")) };
7296
+ }
7297
+ function createBackgroundSessionCard(input) {
7298
+ const title = cardTitle(input.kind);
7299
+ const headerTemplate = cardHeaderTemplate(input.kind);
7300
+ return {
7301
+ body: { elements: [
7302
+ {
7303
+ content: `**${escapeCardText(title)}** · ${escapeCardText(input.displayName)}`,
7304
+ tag: "markdown"
7305
+ },
7306
+ {
7307
+ content: input.text,
7308
+ tag: "markdown"
7309
+ },
7310
+ {
7311
+ content: `会话 ${escapeCardText(input.sessionId)} · _由 Rivus 后台会话生成_`,
7312
+ tag: "markdown"
7313
+ }
7314
+ ] },
7315
+ config: { update_multi: true },
7316
+ header: {
7317
+ template: headerTemplate,
7318
+ title: {
7319
+ content: title,
7320
+ tag: "plain_text"
7321
+ }
7322
+ },
7323
+ schema: "2.0"
7324
+ };
7325
+ }
7326
+ function cardTitle(kind) {
7327
+ switch (kind) {
7328
+ case "progress": return "后台会话进展";
7329
+ case "final": return "后台会话完成";
7330
+ case "failed": return "后台会话失败";
7331
+ case "stopped": return "后台会话已停止";
7332
+ case "reconciliation": return "后台会话需对账";
7333
+ }
7334
+ }
7335
+ function cardHeaderTemplate(kind) {
7336
+ switch (kind) {
7337
+ case "final": return "green";
7338
+ case "failed":
7339
+ case "reconciliation": return "red";
7340
+ case "stopped": return "orange";
7341
+ case "progress": return "blue";
7342
+ }
7343
+ }
7344
+ function escapeCardText(value) {
7345
+ return value.replace(/([*_~`|<>])/g, "\\$1");
7346
+ }
7347
+ function deliveryUuid$1(deliveryId) {
7348
+ return `rivus-${createHash("sha256").update(`background-session:${deliveryId}`).digest("hex").slice(0, 32)}`;
7349
+ }
7350
+ //#endregion
5884
7351
  //#region src/application/memory/rivus-memory-tool.ts
5885
7352
  function createRivusMemoryTool(memory) {
5886
7353
  const handles = Array.isArray(memory) ? [...memory] : [memory];
@@ -7051,21 +8518,16 @@ function createConfiguredFeishuTextReplySender(options) {
7051
8518
  //#region src/infrastructure/feishu/feishu-automation-card-sender.ts
7052
8519
  function createConfiguredFeishuAutomationCardSender(options) {
7053
8520
  const baseUrl = options.config.feishu.baseUrl.replace(/\/$/, "");
7054
- return { send: (input) => Effect.gen(function* () {
7055
- const response = yield* options.client.request({
7056
- body: {
7057
- content: JSON.stringify(createAutomationCard(input.markdown)),
7058
- msg_type: "interactive",
7059
- receive_id: input.receiveId,
7060
- uuid: deliveryUuid(input.idempotencyKey)
7061
- },
7062
- method: "POST",
7063
- url: `${baseUrl}/open-apis/im/v1/messages?receive_id_type=${encodeURIComponent(input.receiveIdType)}`
7064
- }, "Feishu send failed");
7065
- const providerMessageId = readMessageId(response.body.data);
7066
- if (!providerMessageId) return yield* Effect.fail(new FeishuOpenApiError(response.status, response.body.code, "Feishu send response missing message_id"));
7067
- return Object.freeze({ providerMessageId });
7068
- }) };
8521
+ return { send: (input) => sendFeishuInteractiveCard(options.client, {
8522
+ body: {
8523
+ content: JSON.stringify(createAutomationCard(input.markdown)),
8524
+ msg_type: "interactive",
8525
+ receive_id: input.receiveId,
8526
+ uuid: deliveryUuid(input.idempotencyKey)
8527
+ },
8528
+ method: "POST",
8529
+ url: `${baseUrl}/open-apis/im/v1/messages?receive_id_type=${encodeURIComponent(input.receiveIdType)}`
8530
+ }, "Feishu send failed") };
7069
8531
  }
7070
8532
  function createAutomationCard(markdown) {
7071
8533
  const presentation = splitPresentation(markdown);
@@ -7104,11 +8566,6 @@ function splitPresentation(markdown) {
7104
8566
  function deliveryUuid(idempotencyKey) {
7105
8567
  return `rivus-${createHash("sha256").update(idempotencyKey).digest("hex").slice(0, 32)}`;
7106
8568
  }
7107
- function readMessageId(data) {
7108
- if (data === null || typeof data !== "object" || Array.isArray(data)) return void 0;
7109
- const value = data.message_id;
7110
- return typeof value === "string" && value.trim() !== "" ? value : void 0;
7111
- }
7112
8569
  //#endregion
7113
8570
  //#region src/application/interaction/human-interaction-repository.ts
7114
8571
  var HumanInteractionRepositoryError = class extends Error {
@@ -7462,4 +8919,4 @@ function validateDecisionInput(input) {
7462
8919
  if (input.recommendedOptionId && !optionIds.includes(input.recommendedOptionId)) throw new Error("recommended user decision option must be available");
7463
8920
  }
7464
8921
  //#endregion
7465
- export { AgentContextBudgetExceeded, AgentEventHandlerFailed, AgentEventLogStoreError, AgentEventSinkFailed, AgentHarnessBusy, AgentInstanceBusy, AgentInstanceConflict, AgentLoopFailed, AgentMemoryError, AgentRunCancelled, AgentRuntimeDisposed, AutomationMandateError, CardPresentationTransitionDenied, CompactionError, DEFAULT_CARD_STREAM_LEASE_MS, DelegationDenied, DeliveryOutboxError, FeishuCardPresentationNotFound, FeishuCardTargetNotFound, FeishuCardTargetRegistryStoreError, FeishuCotProtocolError, FeishuEndpointCredentialError, FeishuOpenApiError, FeishuTenantAccessTokenError, HumanInteractionRepositoryError, HumanInteractionTransitionDenied, InvalidFeishuCardAction, InvalidFeishuMessageContent, InvalidFeishuSessionReference, InvalidInvocationAuthority, InvalidProjectSkillCatalog, InvalidRecoveryAction, InvalidRivusEndpointBinding, InvalidRivusPlugin, InvalidRivusProjectSpace, InvalidStableJson, InvalidToolInput, InvalidWorkspaceRoot, LangfuseTelemetryConfigError, MEMORY_SCOPES, OpenClawEnvImportError, PluginStateConflict, RIVUS_MEMORY_TOOL_ID, RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_MEMORY_TOOL_VERSION, RIVUS_PLUGIN_API_VERSION, RivusDaemonConfigError, RivusDeploymentAutomationReadinessError, RivusDeploymentDaemonLifecycleError, RivusDeploymentManifestError, RivusDeploymentReadinessError, RivusPluginConformanceError, RivusPluginLoadError, RivusToolInputRejected, SessionSchedulerCapacityExceeded, SessionSchedulerDisposed, ToolInvocationDenied, UnsupportedFeishuCardAction, UnsupportedFeishuMessage, WorkspaceInstructionsSourceError, acceptsCardPresentationProgress, activeCardPresentation, assembleAgentContext, assertRivusPluginConforms, commitAutomationOutcome, createAgentCommandFromFeishuCardAction, createAgentCommandFromFeishuMessage, createAgentConversationMessages, createAgentDomainEventHandler, createAgentDomainEventSink, createAgentDomainEventSinkFromCallback, createAgentHarness, createAgentHarnessClient, createAgentHarnessPooledRuntime, createAgentInstanceRegistry, createAgentLoopFromCallback, createAgentLoopModelExecutionEnd, createAgentLoopModelExecutionStart, createAgentLoopPromptTransformer, createAgentLoopSkillExecutionEnd, createAgentLoopSkillExecutionStart, createAgentLoopTextDelta, createAgentLoopThinkingDelta, createAgentLoopToolExecutionEnd, createAgentLoopToolExecutionStart, createAgentLoopToolExecutionUpdate, createAgentMemoryService, createAgentRunUpdateHandler, createAgentRuntime, createAgentRuntimePool, createAgentTranscriptMessages, createAgentTranscriptTurn, createAgentsMdInstructionsProvider, createAsyncIterableAgentLoop, createAutomationMandateStore, createCoalescingFeishuPublisher, createCompactionService, createCompositeRivusDaemonTransport, createConfiguredFeishuAutomationCardSender, createConfiguredFeishuCardKitPublisher, createConfiguredFeishuCardKitTargetCreator, createConfiguredFeishuCardRolloverRuntime, createConfiguredFeishuHumanInteractionPresenter, createConfiguredFeishuOpenApiClient, createConfiguredFeishuTextReplySender, createConfiguredRivusDaemonBootstrap, createConfiguredRivusDeploymentDaemon, createDailyAutomationSchedule, createDefaultAgentHarness, createDefaultAgentHarnessClient, createDefaultAgentHarnessClientFromCallback, createDefaultAgentHarnessClientFromTextCallback, createDefaultAgentHarnessFromCallback, createDefaultAgentHarnessFromTextCallback, createDefaultAgentRuntime, createDefaultAgentRuntimeFromCallback, createDefaultAgentRuntimeFromTextCallback, createDelegationService, createDeliveryOutbox, createEventAgentLoop, createFakeRivusPlugin, createFeishuAgentDaemon, createFeishuAgentRunCard, createFeishuAgentRuntime, createFeishuCardActionCallbackResponse, createFeishuCardActionErrorResponse, createFeishuCardDeliveryLedger, createFeishuCardDeliveryReconciler, createFeishuCardKitOpenApiClient, createFeishuCardKitOpenApiTargetCreator, createFeishuCardKitPublisher, createFeishuCardPresentationStore, createFeishuCardRollover, createFeishuCardRolloverSupervisor, createFeishuCardTargetPreparation, createFeishuConversationId, createFeishuCotPublisher, createFeishuDeploymentEndpoint, createFeishuEventHandlers, createFeishuHumanInteractionCard, createFeishuHumanInteractionPresenter, createFeishuInboxRepository, createFeishuMessageQueue, createFeishuMessageWorker, createFeishuOpenApiClient, createFeishuPeriodicFlush, createFeishuPresentationPreparation, createFeishuSessionKey, createFeishuStreamProjector, createFeishuTenantAccessTokenProvider, createFeishuWebSocketDaemon, createFeishuWorkerLoop, createFixedClock, createHumanInteractionEndpointRegistry, createHumanInteractionService, createHumanInteractionToolApprovalGateway, createInMemoryFeishuCardTargetRegistry, createInMemoryHumanInteractionRepository, createInvocationAuthority, createJsonFetchRequest, createJsonFileFeishuCardTargetRegistry, createJsonlAgentEventLog, createJsonlHumanInteractionRepository, createLangfuseAgentTelemetry, createLazyFeishuWebSocketEventDispatcher, createMemoryNamespace, createOpenTelemetryAgentEventSink, createOpenTelemetryAgentTelemetry, createPiAgentLoop, createPiSdkAgentLoop, createPiSessionRegistry, createPluginStateStore, createProjectMemoryPromptPreparer, createRateLimitedFeishuPublisher, createRecoveryAction, createRecoveryControl, createRivusAgentHost, createRivusDaemonProcess, createRivusDaemonShutdownController, createRivusDaemonStatusHttpServer, createRivusDaemonStatusReporter, createRivusDeploymentCliProcess, createRivusDeploymentDaemon, createRivusEnvFromOpenClawConfig, createRivusMemoryTool, createRivusMemoryToolContract, createRivusMemoryToolDescriptor, createRivusPluginCatalog, createRoutedHumanInteractionToolApprovalService, createScheduledAutomation, createSequenceRunIds, createSessionScheduler, createSubagentCoordinator, createSystemClock, createTelemetryContentRedactor, createTestClock, createTextAgentLoop, createTextAgentLoopFromCallback, createToolBroker, createToolInputDigest, createToolOperationLedger, createUuidRunIds, createWorkspaceRootHandle, describeFeishuMessageIntake, evolveAgentRun, formatRivusEnvFile, initialAgentRunState, intersectToolIds, isAgentToolExecutionEvent, isAssistantTextDeltaEvent, isAssistantThinkingDeltaEvent, isCardPresentationHandoffDue, isTerminalAgentDomainEvent, isTerminalAgentRunPhase, loadNodeRivusPluginModule, loadRivusDaemonConfig, loadRivusDeployment, loadRivusDeploymentManifest, normalizeStableJson, openJsonAutomationTickRepository, openJsonlAgentMemoryService, openJsonlFeishuCardDeliveryLedger, openJsonlFeishuInboxRepository, openJsonlRecoveryControl, openJsonlToolOperationLedger, replayAgentHistory, replayAgentTranscript, requiresToolApproval, resolveFeishuEndpointCredentials, resolveLangfuseTelemetryConfig, resolveRivusAgentDefinition, resolveRivusProjectSpace, restoreAgentHistory, restoreConfiguredRivusDaemonBootstrap, restrictMemoryScopesForAudience, runRivusDaemonCli, shouldAcceptFeishuEndpointMessage, transitionHumanInteraction, validateProjectSkillCatalog, validateProjectSkillCommand, validateRivusDeploymentManifest };
8922
+ export { AgentContextBudgetExceeded, AgentEventHandlerFailed, AgentEventLogStoreError, AgentEventSinkFailed, AgentHarnessBusy, AgentInstanceBusy, AgentInstanceConflict, AgentLoopFailed, AgentMemoryError, AgentRunCancelled, AgentRuntimeDisposed, AutomationMandateError, BACKGROUND_SESSION_DELIVERY_JSONL_VERSION, BACKGROUND_SESSION_JSONL_VERSION, BACKGROUND_SESSION_SESSION_KEY_PREFIX, BACKGROUND_SESSION_START_TOOL_ID, BACKGROUND_SESSION_TOOL_IDS, BACKGROUND_SESSION_TOOL_PLUGIN_ID, BACKGROUND_SESSION_TOOL_VERSION, BackgroundSessionCallerDenied, BackgroundSessionDeliveryConflict, BackgroundSessionRepositoryConflict, BackgroundSessionRepositoryCorrupted, BackgroundSessionTransitionDenied, CardPresentationTransitionDenied, CompactionError, DEFAULT_BACKGROUND_SESSION_LEASE_MS, DEFAULT_BACKGROUND_SESSION_LEASE_RENEWAL_INTERVAL_MS, DEFAULT_BACKGROUND_SESSION_LIFETIME_MS, DEFAULT_BACKGROUND_SESSION_MAX_CONCURRENT_SESSIONS, DEFAULT_BACKGROUND_SESSION_MAX_CONSECUTIVE_FAILURES, DEFAULT_BACKGROUND_SESSION_RETRY_BACKOFF_MS, DEFAULT_BACKGROUND_SESSION_STEP_TIMEOUT_MS, DEFAULT_BACKGROUND_SESSION_SUPERVISOR_INTERVAL_MS, DEFAULT_CARD_STREAM_LEASE_MS, DelegationDenied, DeliveryOutboxError, FeishuCardPresentationNotFound, FeishuCardTargetNotFound, FeishuCardTargetRegistryStoreError, FeishuCotProtocolError, FeishuEndpointCredentialError, FeishuOpenApiError, FeishuTenantAccessTokenError, HumanInteractionRepositoryError, HumanInteractionTransitionDenied, InvalidFeishuCardAction, InvalidFeishuMessageContent, InvalidFeishuSessionReference, InvalidInvocationAuthority, InvalidProjectSkillCatalog, InvalidRecoveryAction, InvalidRivusEndpointBinding, InvalidRivusPlugin, InvalidRivusProjectSpace, InvalidStableJson, InvalidToolInput, InvalidWorkspaceRoot, LangfuseTelemetryConfigError, MEMORY_SCOPES, OpenClawEnvImportError, PluginStateConflict, RIVUS_MEMORY_TOOL_ID, RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_MEMORY_TOOL_VERSION, RIVUS_PLUGIN_API_VERSION, RivusDaemonConfigError, RivusDeploymentAutomationReadinessError, RivusDeploymentDaemonLifecycleError, RivusDeploymentManifestError, RivusDeploymentReadinessError, RivusPluginConformanceError, RivusPluginLoadError, RivusToolInputRejected, SessionSchedulerCapacityExceeded, SessionSchedulerDisposed, ToolInvocationDenied, UnsupportedFeishuCardAction, UnsupportedFeishuMessage, WorkspaceInstructionsSourceError, acceptsCardPresentationProgress, activeCardPresentation, appendBackgroundSessionInput, assembleAgentContext, assertRivusPluginConforms, backgroundSessionToolIds, claimBackgroundSession, commitAutomationOutcome, completeBackgroundSessionStep, completeBackgroundSessionStop, createAgentCommandFromFeishuCardAction, createAgentCommandFromFeishuMessage, createAgentConversationMessages, createAgentDomainEventHandler, createAgentDomainEventSink, createAgentDomainEventSinkFromCallback, createAgentHarness, createAgentHarnessClient, createAgentHarnessPooledRuntime, createAgentInstanceRegistry, createAgentLoopFromCallback, createAgentLoopModelExecutionEnd, createAgentLoopModelExecutionStart, createAgentLoopPromptTransformer, createAgentLoopSkillExecutionEnd, createAgentLoopSkillExecutionStart, createAgentLoopTextDelta, createAgentLoopThinkingDelta, createAgentLoopToolExecutionEnd, createAgentLoopToolExecutionStart, createAgentLoopToolExecutionUpdate, createAgentMemoryService, createAgentRunUpdateHandler, createAgentRuntime, createAgentRuntimePool, createAgentTranscriptMessages, createAgentTranscriptTurn, createAgentsMdInstructionsProvider, createAsyncIterableAgentLoop, createAutomationMandateStore, createBackgroundSession, createBackgroundSessionCard, createBackgroundSessionDeliveryStore, createBackgroundSessionHostTools, createBackgroundSessionKey, createBackgroundSessionRepository, createBackgroundSessionService, createBackgroundSessionStepSourceMessageId, createBackgroundSessionSupervisor, createBackgroundSessionToolContracts, createCoalescingFeishuPublisher, createCompactionService, createCompositeRivusDaemonTransport, createConfiguredFeishuAutomationCardSender, createConfiguredFeishuBackgroundSessionDelivery, createConfiguredFeishuCardKitPublisher, createConfiguredFeishuCardKitTargetCreator, createConfiguredFeishuCardRolloverRuntime, createConfiguredFeishuHumanInteractionPresenter, createConfiguredFeishuOpenApiClient, createConfiguredFeishuTextReplySender, createConfiguredRivusDaemonBootstrap, createConfiguredRivusDeploymentDaemon, createDailyAutomationSchedule, createDefaultAgentHarness, createDefaultAgentHarnessClient, createDefaultAgentHarnessClientFromCallback, createDefaultAgentHarnessClientFromTextCallback, createDefaultAgentHarnessFromCallback, createDefaultAgentHarnessFromTextCallback, createDefaultAgentRuntime, createDefaultAgentRuntimeFromCallback, createDefaultAgentRuntimeFromTextCallback, createDelegationService, createDeliveryOutbox, createEventAgentLoop, createFakeRivusPlugin, createFeishuAgentDaemon, createFeishuAgentRunCard, createFeishuAgentRuntime, createFeishuCardActionCallbackResponse, createFeishuCardActionErrorResponse, createFeishuCardDeliveryLedger, createFeishuCardDeliveryReconciler, createFeishuCardKitOpenApiClient, createFeishuCardKitOpenApiTargetCreator, createFeishuCardKitPublisher, createFeishuCardPresentationStore, createFeishuCardRollover, createFeishuCardRolloverSupervisor, createFeishuCardTargetPreparation, createFeishuConversationId, createFeishuCotPublisher, createFeishuDeploymentEndpoint, createFeishuEventHandlers, createFeishuHumanInteractionCard, createFeishuHumanInteractionPresenter, createFeishuInboxRepository, createFeishuMessageQueue, createFeishuMessageWorker, createFeishuOpenApiClient, createFeishuPeriodicFlush, createFeishuPresentationPreparation, createFeishuSessionKey, createFeishuStreamProjector, createFeishuTenantAccessTokenProvider, createFeishuWebSocketDaemon, createFeishuWorkerLoop, createFixedClock, createHumanInteractionEndpointRegistry, createHumanInteractionService, createHumanInteractionToolApprovalGateway, createInMemoryFeishuCardTargetRegistry, createInMemoryHumanInteractionRepository, createInvocationAuthority, createJsonFetchRequest, createJsonFileFeishuCardTargetRegistry, createJsonlAgentEventLog, createJsonlHumanInteractionRepository, createLangfuseAgentTelemetry, createLazyFeishuWebSocketEventDispatcher, createMemoryNamespace, createOpenTelemetryAgentEventSink, createOpenTelemetryAgentTelemetry, createPiAgentLoop, createPiSdkAgentLoop, createPiSessionRegistry, createPluginStateStore, createProjectMemoryPromptPreparer, createRateLimitedFeishuPublisher, createRecoveryAction, createRecoveryControl, createRivusAgentHost, createRivusDaemonProcess, createRivusDaemonShutdownController, createRivusDaemonStatusHttpServer, createRivusDaemonStatusReporter, createRivusDeploymentCliProcess, createRivusDeploymentDaemon, createRivusEnvFromOpenClawConfig, createRivusMemoryTool, createRivusMemoryToolContract, createRivusMemoryToolDescriptor, createRivusPluginCatalog, createRoutedHumanInteractionToolApprovalService, createScheduledAutomation, createSequenceRunIds, createSessionScheduler, createSubagentCoordinator, createSystemClock, createTelemetryContentRedactor, createTestClock, createTextAgentLoop, createTextAgentLoopFromCallback, createToolBroker, createToolInputDigest, createToolOperationLedger, createUuidRunIds, createWorkspaceRootHandle, describeFeishuMessageIntake, evolveAgentRun, extendBackgroundSessionDefinition, failBackgroundSessionStep, formatRivusEnvFile, initialAgentRunState, intersectToolIds, isAgentToolExecutionEvent, isAssistantTextDeltaEvent, isAssistantThinkingDeltaEvent, isBackgroundSessionDue, isBackgroundSessionLeaseExpired, isBackgroundSessionState, isBackgroundSessionTerminalPhase, isBackgroundSessionToolId, isCardPresentationHandoffDue, isTerminalAgentDomainEvent, isTerminalAgentRunPhase, loadNodeRivusPluginModule, loadRivusDaemonConfig, loadRivusDeployment, loadRivusDeploymentManifest, narrowBackgroundSessionDefinition, normalizeStableJson, openJsonAutomationTickRepository, openJsonlAgentMemoryService, openJsonlBackgroundSessionDeliveryStore, openJsonlBackgroundSessionRepository, openJsonlFeishuCardDeliveryLedger, openJsonlFeishuInboxRepository, openJsonlRecoveryControl, openJsonlToolOperationLedger, parkBackgroundSessionForReconciliation, progressDeliveryId, releaseBackgroundSessionLease, renewBackgroundSessionLease, replayAgentHistory, replayAgentTranscript, requestBackgroundSessionStop, requeueInterruptedBackgroundSessionStep, requiresToolApproval, resolveBackgroundSessionReconciliation, resolveBackgroundSessionSupervisorIntervalMs, resolveFeishuEndpointCredentials, resolveLangfuseTelemetryConfig, resolveRivusAgentDefinition, resolveRivusProjectSpace, restoreAgentHistory, restoreConfiguredRivusDaemonBootstrap, restrictMemoryScopesForAudience, runRivusDaemonCli, sessionIdFromSessionKey, shouldAcceptFeishuEndpointMessage, suspendBackgroundSession, terminalDeliveryId, transitionHumanInteraction, validateProjectSkillCatalog, validateProjectSkillCommand, validateRivusDeploymentManifest };