File size: 2,654 Bytes
5cb63c1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/**
 * Configured binding target lifecycle helpers.
 *
 * Ensures or resets stateful binding targets through registered target drivers.
 */
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { ConfiguredBindingResolution } from "./binding-types.js";
import {
  ensureStatefulTargetBuiltinsRegistered,
  isStatefulTargetBuiltinDriverId,
} from "./stateful-target-builtins.js";
import {
  getStatefulBindingTargetDriver,
  resolveStatefulBindingTargetBySessionKey,
  type StatefulBindingTargetResetResult,
} from "./stateful-target-drivers.js";

/**
 * Ensures the stateful target driver for a configured binding is ready to receive traffic.
 */
export async function ensureConfiguredBindingTargetReady(params: {
  cfg: OpenClawConfig;
  bindingResolution: ConfiguredBindingResolution | null;
}): Promise<{ ok: true } | { ok: false; error: string }> {
  if (!params.bindingResolution) {
    return { ok: true };
  }
  const driverId = params.bindingResolution.statefulTarget.driverId;
  let driver = getStatefulBindingTargetDriver(driverId);
  // Built-in drivers are registered lazily so normal channel startup does not load every
  // stateful target implementation before a binding actually needs one.
  if (!driver && isStatefulTargetBuiltinDriverId(driverId)) {
    await ensureStatefulTargetBuiltinsRegistered();
    driver = getStatefulBindingTargetDriver(driverId);
  }
  if (!driver) {
    return {
      ok: false,
      error: `Configured binding target driver unavailable: ${driverId}`,
    };
  }
  return await driver.ensureReady({
    cfg: params.cfg,
    bindingResolution: params.bindingResolution,
  });
}

/**
 * Resets a stateful configured binding target in place when its driver supports reset.
 */
export async function resetConfiguredBindingTargetInPlace(params: {
  cfg: OpenClawConfig;
  sessionKey: string;
  agentId?: string;
  reason: "new" | "reset";
  commandSource?: string;
}): Promise<StatefulBindingTargetResetResult> {
  let resolved = resolveStatefulBindingTargetBySessionKey({
    cfg: params.cfg,
    sessionKey: params.sessionKey,
    agentId: params.agentId,
  });
  if (!resolved) {
    await ensureStatefulTargetBuiltinsRegistered();
    resolved = resolveStatefulBindingTargetBySessionKey({
      cfg: params.cfg,
      sessionKey: params.sessionKey,
      agentId: params.agentId,
    });
  }
  if (!resolved?.driver.resetInPlace) {
    // A missing reset hook is a valid skip, not a hard routing failure.
    return {
      ok: false,
      skipped: true,
    };
  }
  return await resolved.driver.resetInPlace({
    ...params,
    bindingTarget: resolved.bindingTarget,
  });
}