mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
refactor(worker): split live session binding
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import type { SessionIdentityMutation } from "../../config/sessions/session-accessor.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { WorkerLiveTrajectoryTarget } from "./live-event-projection.js";
|
||||
import { resolveWorkerSessionTarget } from "./session-target.js";
|
||||
|
||||
export type LiveEventTarget = WorkerLiveTrajectoryTarget;
|
||||
|
||||
export type WorkerLiveSessionBinding = Readonly<{
|
||||
environmentId: string;
|
||||
runEpoch: number;
|
||||
sessionId: string;
|
||||
}>;
|
||||
|
||||
export type BoundLiveSession = WorkerLiveSessionBinding & { target: LiveEventTarget };
|
||||
|
||||
export function isValidLiveSessionBinding(binding: WorkerLiveSessionBinding): boolean {
|
||||
return (
|
||||
binding.environmentId.length > 0 &&
|
||||
binding.sessionId.length > 0 &&
|
||||
Number.isSafeInteger(binding.runEpoch) &&
|
||||
binding.runEpoch >= 0
|
||||
);
|
||||
}
|
||||
|
||||
function resolveLiveEventTarget(
|
||||
config: OpenClawConfig,
|
||||
sessionId: string,
|
||||
): LiveEventTarget | undefined {
|
||||
const target = resolveWorkerSessionTarget(config, sessionId);
|
||||
if (!target) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
...(target.agentId ? { agentId: target.agentId } : {}),
|
||||
sessionId: target.sessionId,
|
||||
sessionKey: target.sessionKey,
|
||||
storePath: target.storePath,
|
||||
};
|
||||
}
|
||||
|
||||
function prepareBoundLiveSession(
|
||||
config: OpenClawConfig,
|
||||
binding: WorkerLiveSessionBinding,
|
||||
): BoundLiveSession | undefined {
|
||||
if (!isValidLiveSessionBinding(binding)) {
|
||||
return undefined;
|
||||
}
|
||||
const target = resolveLiveEventTarget(config, binding.sessionId);
|
||||
return target ? { ...binding, target } : undefined;
|
||||
}
|
||||
|
||||
export function prepareBoundLiveSessionSafely(
|
||||
config: OpenClawConfig,
|
||||
binding: WorkerLiveSessionBinding,
|
||||
): BoundLiveSession | undefined {
|
||||
try {
|
||||
return prepareBoundLiveSession(config, binding);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function matchesSessionIdentityMutation(
|
||||
binding: WorkerLiveSessionBinding,
|
||||
prepared: BoundLiveSession | undefined,
|
||||
mutation: SessionIdentityMutation,
|
||||
): boolean {
|
||||
const targets =
|
||||
"current" in mutation ? [mutation.previous, mutation.current] : [mutation.previous];
|
||||
return targets.some(
|
||||
(target) =>
|
||||
target.sessionId === binding.sessionId ||
|
||||
(prepared ? target.sessionKeys.includes(prepared.target.sessionKey) : false),
|
||||
);
|
||||
}
|
||||
@@ -4,10 +4,7 @@ import type {
|
||||
WorkerLiveEventParams,
|
||||
WorkerLiveEventResult,
|
||||
} from "../../../packages/gateway-protocol/src/schema/worker-admission.js";
|
||||
import {
|
||||
onSessionIdentityMutation,
|
||||
type SessionIdentityMutation,
|
||||
} from "../../config/sessions/session-accessor.js";
|
||||
import { onSessionIdentityMutation } from "../../config/sessions/session-accessor.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import {
|
||||
claimAgentRunContext,
|
||||
@@ -26,9 +23,15 @@ import {
|
||||
prepareWorkerLiveEventData,
|
||||
recordWorkerLiveTrajectoryEvent,
|
||||
type WorkerLiveTrajectoryRecorder,
|
||||
type WorkerLiveTrajectoryTarget,
|
||||
} from "./live-event-projection.js";
|
||||
import { resolveWorkerSessionTarget } from "./session-target.js";
|
||||
import {
|
||||
isValidLiveSessionBinding,
|
||||
matchesSessionIdentityMutation,
|
||||
prepareBoundLiveSessionSafely,
|
||||
type BoundLiveSession,
|
||||
type LiveEventTarget,
|
||||
type WorkerLiveSessionBinding,
|
||||
} from "./live-event-session-binding.js";
|
||||
|
||||
const DEFAULT_WINDOW_SIZE = 128;
|
||||
const DEFAULT_MAX_PENDING_BYTES = 512 * 1024;
|
||||
@@ -49,16 +52,6 @@ type OwnedLiveRun = {
|
||||
trajectoryRecorder: WorkerLiveTrajectoryRecorder;
|
||||
};
|
||||
|
||||
type LiveEventTarget = WorkerLiveTrajectoryTarget;
|
||||
|
||||
type WorkerLiveSessionBinding = Readonly<{
|
||||
environmentId: string;
|
||||
runEpoch: number;
|
||||
sessionId: string;
|
||||
}>;
|
||||
|
||||
type BoundLiveSession = WorkerLiveSessionBinding & { target: LiveEventTarget };
|
||||
|
||||
type WorkerLiveCredentialRotation = Readonly<{
|
||||
credentialHash: string;
|
||||
environmentId: string;
|
||||
@@ -105,67 +98,6 @@ function capacityExceeded(): WorkerLiveEventFailure {
|
||||
return { ok: false, details: { reason: "capacity-exceeded" } };
|
||||
}
|
||||
|
||||
function resolveLiveEventTarget(
|
||||
config: OpenClawConfig,
|
||||
sessionId: string,
|
||||
): LiveEventTarget | undefined {
|
||||
const target = resolveWorkerSessionTarget(config, sessionId);
|
||||
if (!target) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
...(target.agentId ? { agentId: target.agentId } : {}),
|
||||
sessionId: target.sessionId,
|
||||
sessionKey: target.sessionKey,
|
||||
storePath: target.storePath,
|
||||
};
|
||||
}
|
||||
|
||||
function prepareBoundLiveSession(
|
||||
config: OpenClawConfig,
|
||||
binding: WorkerLiveSessionBinding,
|
||||
): BoundLiveSession | undefined {
|
||||
if (!isValidLiveSessionBinding(binding)) {
|
||||
return undefined;
|
||||
}
|
||||
const target = resolveLiveEventTarget(config, binding.sessionId);
|
||||
return target ? { ...binding, target } : undefined;
|
||||
}
|
||||
|
||||
function isValidLiveSessionBinding(binding: WorkerLiveSessionBinding): boolean {
|
||||
return (
|
||||
binding.environmentId.length > 0 &&
|
||||
binding.sessionId.length > 0 &&
|
||||
Number.isSafeInteger(binding.runEpoch) &&
|
||||
binding.runEpoch >= 0
|
||||
);
|
||||
}
|
||||
|
||||
function prepareBoundLiveSessionSafely(
|
||||
config: OpenClawConfig,
|
||||
binding: WorkerLiveSessionBinding,
|
||||
): BoundLiveSession | undefined {
|
||||
try {
|
||||
return prepareBoundLiveSession(config, binding);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function matchesSessionIdentityMutation(
|
||||
binding: WorkerLiveSessionBinding,
|
||||
prepared: BoundLiveSession | undefined,
|
||||
mutation: SessionIdentityMutation,
|
||||
): boolean {
|
||||
const targets =
|
||||
"current" in mutation ? [mutation.previous, mutation.current] : [mutation.previous];
|
||||
return targets.some(
|
||||
(target) =>
|
||||
target.sessionId === binding.sessionId ||
|
||||
(prepared ? target.sessionKeys.includes(prepared.target.sessionKey) : false),
|
||||
);
|
||||
}
|
||||
|
||||
export function createWorkerLiveEventReceiver(options: WorkerLiveEventReceiverOptions) {
|
||||
const boundSessions = new Map<string, BoundLiveSession>();
|
||||
const sessionBindings = new Map<string, WorkerLiveSessionBinding>();
|
||||
|
||||
@@ -637,7 +637,7 @@ describe("worker turn launcher", () => {
|
||||
sessionKey: SESSION_KEY,
|
||||
agentId: "main",
|
||||
});
|
||||
expect(tunnel.reconcileWorkspace).toHaveBeenCalledWith(
|
||||
expect(vi.mocked(tunnel.reconcileWorkspace)).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ localPath: root }),
|
||||
);
|
||||
const conflictSummary =
|
||||
|
||||
Reference in New Issue
Block a user