openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
274 lines (273 loc) • 13.9 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs";
import { r as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import "./session-key-DY3MOX4N.mjs";
import { h as parseAgentSessionKey } from "./session-key-utils-CDyBC9Gn.mjs";
import { l as resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db.paths-BbmZlEP5.mjs";
import { i as toDatabaseOptions } from "./session-accessor.sqlite-scope-helpers-CfDTAEsL.mjs";
import { s as normalizeDeliveryContext } from "./delivery-context.shared-BYdFKp9k.mjs";
import { n as captureSessionStoreCandidateIdentities, t as assertSessionStoreReadCandidate } from "./session-store-read-candidates-CXD-JYGz.mjs";
import { t as captureSessionTranscriptStorageEnvironment } from "./transcript-target-binding-DpcuSIFy.mjs";
import { f as bindGatewayContextResolver } from "./gateway-request-scope-DV3FHtde.mjs";
import { a as composeSessionSourceAssertion, l as releaseSessionSourceAuthorities } from "./session-source-authority-h1UO3u0I.mjs";
import { i as rethrowIncognitoSessionError } from "./incognito-session-error-BUzgcwoZ.mjs";
import { s as createSessionWorkStartChangedError } from "./work-start-error-Dh9d0ImY.mjs";
import { i as prepareSqliteScope } from "./session-accessor.sqlite-scope-BkgwxatT.mjs";
import { t as captureIncognitoSessionBinding } from "./session-incognito-binding-Dp6RTei2.mjs";
import { t as loadExactSessionEntry } from "./session-accessor.sqlite-exact-read-HBi2gDDN.mjs";
import { i as retainSessionHistoryWorkerDatabase } from "./session-transcript-worker-runtime-BdmdicNg.mjs";
import { n as resolveSessionTranscriptReadFence } from "./session-transcript-read-fence-DqVaDIch.mjs";
import { n as decodeSessionTranscriptWorkerReadError } from "./session-history-worker-errors-DRVUiJbS.mjs";
import { h as normalizeInputProvenance } from "./input-provenance-B5YZS2Do.mjs";
import { t as captureSessionStoreReadCandidates } from "./session-store-target-inventory-C9ERDnSH.mjs";
import "./session-accessor-C3ljJ974.mjs";
import "./lifecycle-BJGMGqxC.mjs";
import { t as readAdmittedHarnessCompletionInput } from "./session-harness-completion-source.kernel-Uf_MmyFd.mjs";
import { n as sourceDeliveryTargetsMatch } from "./source-delivery-plan-6BT8ZkBu.mjs";
import { AsyncLocalStorage } from "node:async_hooks";
//#region src/agents/agent-harness-completion-scope.ts
const scopeRegistry = resolveGlobalSingleton(Symbol.for("openclaw.agentHarnessCompletionScope.registry"), () => ({ hostIssuedScopes: /* @__PURE__ */ new WeakSet() }));
/** Creates a host-issued requester scope for agent harness completion. */
function createAgentHarnessCompletionScope(params) {
const requesterSessionKey = params.requesterSessionKey.trim();
if (!requesterSessionKey) throw new Error("Harness completion scope requires requesterSessionKey");
const requesterAgentId = params.requesterAgentId?.trim() || parseAgentSessionKey(requesterSessionKey)?.agentId;
if (!requesterAgentId) throw new Error("Harness completion scope requires an exact requester agent");
const requesterOrigin = normalizeDeliveryContext(params.requesterOrigin);
const scope = {
requesterSessionKey,
requesterAgentId,
...requesterOrigin ? { requesterOrigin } : {}
};
scopeRegistry.hostIssuedScopes.add(scope);
bindGatewayContextResolver(scope, params.gatewayContextResolver);
return scope;
}
function assertAgentHarnessCompletionScope(scope) {
if (!scopeRegistry.hostIssuedScopes.has(scope)) throw new Error("Harness completion requires a host-issued scope");
return scope;
}
const sourceAdmissions = resolveGlobalSingleton(Symbol.for("openclaw.harnessCompletionSourceAdmission"), () => new AsyncLocalStorage());
/** The native source owner admits delivery; the requester receipt owns accepted recovery thereafter. */
async function withAgentHarnessCompletionAdmission(params, operation) {
const scope = assertAgentHarnessCompletionScope(params.scope);
let active = true;
const assertCurrent = () => {
if (!active || !params.isSourceCurrent()) throw new Error("Harness completion source owner retired");
};
assertCurrent();
try {
return await sourceAdmissions.run({
...params,
scope,
assertCurrent
}, operation);
} finally {
active = false;
}
}
function assertHarnessCompletionSourceAdmission(params) {
const admission = sourceAdmissions.getStore();
if (!admission || admission.scope.requesterSessionKey !== params.requesterSessionKey || admission.scope.requesterAgentId !== params.requesterAgentId || admission.requesterSessionId !== params.requesterSessionId || admission.requesterLifecycleRevision !== params.requesterLifecycleRevision || admission.sourceSessionKey !== params.sourceSessionKey || admission.sourceRunId !== params.sourceRunId) throw new Error("Harness completion requires exact host-issued source admission");
admission.assertCurrent();
return admission.assertCurrent;
}
//#endregion
//#region src/agents/agent-harness-completion-recovery.ts
/** These receipts are stricter than legacy live-return classification: omission is not success. */
function hasHarnessCompletionFinalReceipt(receipt) {
const target = receipt.deliveryContext;
if (!target?.channel || !target.to || receipt.payloadsTruncated || receipt.messagingToolSentTargetsTruncated || receipt.messagingToolAggregateEvidenceUnaccounted) return false;
const requiredProvider = normalizeOptionalString(target.channel)?.toLowerCase();
if (!requiredProvider) return false;
if (receipt.messagingToolSentTargets?.some((sent) => normalizeOptionalString(sent.provider)?.toLowerCase() === requiredProvider && normalizeOptionalString(sent.accountId) === normalizeOptionalString(target.accountId) && sent.sourceReplyFinal === true && sent.visible === true && sourceDeliveryTargetsMatch(sent, target))) return true;
return receipt.deliveryStatus?.status === "sent" && (receipt.deliveryStatus.resultCount ?? 0) > 0 && receipt.payloads?.some((payload) => payload.visible === true) === true;
}
const admittedClaims = /* @__PURE__ */ new WeakMap();
function sameCompletionClaim(left, right) {
return Boolean(left && left.taskId === right.taskId && left.taskRunId === right.taskRunId && left.sourceRunId === right.sourceRunId && left.requesterSessionKey === right.requesterSessionKey && left.requesterAgentId === right.requesterAgentId && left.sessionId === right.sessionId && left.lifecycleRevision === right.lifecycleRevision);
}
function captureHarnessCompletionRecovery(params) {
const provenance = normalizeInputProvenance(params.inputProvenance);
if (!params.runId.startsWith("announce:") || provenance?.kind !== "inter_session" || !["agent_harness_task", "agent_harness_completion"].includes(provenance.sourceTool ?? "") || provenance.sourceChannel !== "internal" || !provenance.sourceSessionKey) return;
const assertSourceCurrent = assertHarnessCompletionSourceAdmission({
requesterSessionKey: params.sessionKey,
requesterAgentId: params.agentId,
requesterSessionId: params.entry.sessionId,
requesterLifecycleRevision: params.entry.lifecycleRevision,
sourceSessionKey: provenance.sourceSessionKey,
sourceRunId: params.runId
});
const claim = {
taskId: provenance.sourceSessionKey,
taskRunId: provenance.sourceSessionKey,
taskStatus: "succeeded",
sourceRunId: params.runId,
requesterSessionKey: params.sessionKey,
requesterAgentId: params.agentId,
sessionId: params.entry.sessionId,
...params.entry.lifecycleRevision ? { lifecycleRevision: params.entry.lifecycleRevision } : {}
};
admittedClaims.set(claim, assertSourceCurrent);
return claim;
}
/** A current session incarnation and its exact admitted completion receipt own further effects. */
function getOwedHarnessCompletionTask(claim, entry) {
if (entry.sessionId !== claim.sessionId || entry.lifecycleRevision !== claim.lifecycleRevision) return;
if (entry.restartRecoveryTerminalDeliveryEvidence?.some((receipt) => sameCompletionClaim(receipt.harnessCompletion, claim) && hasHarnessCompletionFinalReceipt(receipt))) return;
if (sameCompletionClaim(entry.restartRecoveryHarnessCompletion, claim) || entry.restartRecoveryTerminalDeliveryEvidence?.some((receipt) => sameCompletionClaim(receipt.harnessCompletion, claim))) return claim;
const assertSourceCurrent = admittedClaims.get(claim);
if (!assertSourceCurrent) return;
try {
assertSourceCurrent();
return claim;
} catch (error) {
rethrowIncognitoSessionError(error);
return;
}
}
/** The existing admitted execution guard rechecks this before execution and delegated effects. */
function createHarnessCompletionSourceAssertion(params) {
const target = {
agentId: params.claim.requesterAgentId,
sessionKey: params.claim.requesterSessionKey,
storePath: params.storePath
};
const binding = captureIncognitoSessionBinding(target);
const capturedClaim = binding?.actor.sessions.captureCurrent(target.sessionKey);
const refuse = () => {
throw createSessionWorkStartChangedError(target.sessionKey);
};
const assertIncognitoClaim = () => {
if (!binding) return refuse();
binding.admissionSignal?.throwIfAborted();
binding.actor.assertReadable();
capturedClaim?.assertCurrent();
const entry = binding.actor.sessions.readSteering(target.sessionKey);
if (!entry || !getOwedHarnessCompletionTask(params.claim, entry)) return refuse();
return entry;
};
const prepareIncognitoSource = async () => {
if (!binding) return refuse();
assertIncognitoClaim();
const retained = await binding.actor.sessions.retainCompletionSource({ assertCurrent: assertIncognitoClaim }, {
sessionKey: target.sessionKey,
sessionId: params.claim.sessionId,
lifecycleRevision: params.claim.lifecycleRevision,
claim: params.claim,
admission: resolveSessionTranscriptReadFence({
agentId: target.agentId,
sessionId: params.claim.sessionId
})
}, binding.admissionSignal);
return {
assertCurrent: () => {
assertIncognitoClaim();
retained.assertCurrent();
},
checks: [],
release: () => retained.release()
};
};
const prepareSnapshot = (snapshot, source, assertStorageCurrent, release) => {
const assertCurrent = () => {
assertStorageCurrent();
if (!snapshot.entry || !getOwedHarnessCompletionTask(params.claim, snapshot.entry)) refuse();
if (snapshot.readError) throw decodeSessionTranscriptWorkerReadError(snapshot.readError);
if (!snapshot.validInput) refuse();
};
assertCurrent();
return {
assertCurrent,
checks: [{
predicate: {
source,
sessionKey: target.sessionKey,
fields: [
"sessionId",
"lifecycleRevision",
"restartRecoveryHarnessCompletion",
"restartRecoveryTerminalDeliveryEvidence",
"restartRecoveryDeliveryRunId",
"restartRecoveryRuns"
],
expected: snapshot.entry,
...snapshot.version ? { transcript: {
sessionId: params.claim.sessionId,
version: snapshot.version
} } : {}
},
refuse
}],
release
};
};
const assertSource = () => {
if (binding) {
if (assertIncognitoClaim().restartRecoveryDeliveryRunId !== params.claim.sourceRunId) refuse();
return;
}
const current = loadExactSessionEntry({
...target,
readConsistency: "latest"
});
if (!current || current.sessionKey !== params.claim.requesterSessionKey || !getOwedHarnessCompletionTask(params.claim, current.entry) || current.entry.restartRecoveryDeliveryRunId !== params.claim.sourceRunId && !readAdmittedHarnessCompletionInput({
claim: params.claim,
entry: current.entry,
storePath: params.storePath,
operationalRunId: current.entry.restartRecoveryDeliveryRunId
})) throw createSessionWorkStartChangedError(params.claim.requesterSessionKey);
};
return composeSessionSourceAssertion([params.priorAssertion, Object.assign(assertSource, {
prepareSessionSourceScope: binding ? prepareIncognitoSource : void 0,
async prepareSessionSource() {
const { claim } = params;
if (binding) return prepareIncognitoSource();
const env = captureSessionTranscriptStorageEnvironment(process.env);
const candidates = captureSessionStoreReadCandidates(params.storePath);
const identities = captureSessionStoreCandidateIdentities(candidates);
const admission = resolveSessionTranscriptReadFence({
agentId: claim.requesterAgentId,
sessionId: claim.sessionId
});
const resolved = await prepareSqliteScope({
agentId: claim.requesterAgentId,
sessionKey: claim.requesterSessionKey,
storePath: params.storePath,
env
});
const options = toDatabaseOptions(resolved);
const path = resolveOpenClawAgentSqlitePath(options);
const identity = identities.get(assertSessionStoreReadCandidate(path, candidates));
if (!identity?.key.startsWith("file:")) return refuse();
const source = {
agentId: options.agentId,
path,
databaseIdentity: identity.key.slice(5),
databaseBirthtime: identity.birthtime
};
const retained = retainSessionHistoryWorkerDatabase({
...options,
path
});
try {
const snapshot = await retained.owner.readHarnessCompletionSource({
env,
claim,
source,
...admission ? { admission } : {}
});
return prepareSnapshot(snapshot, source, () => {
retained.owner.assertCurrent();
assertSessionStoreReadCandidate(path, candidates);
assertExistingDatabaseIdentity(path, identity.key, identity.birthtime);
}, retained.release);
} catch (error) {
await releaseSessionSourceAuthorities([retained], [error]);
throw error;
}
}
})]);
}
//#endregion
export { assertAgentHarnessCompletionScope as a, hasHarnessCompletionFinalReceipt as i, createHarnessCompletionSourceAssertion as n, createAgentHarnessCompletionScope as o, getOwedHarnessCompletionTask as r, withAgentHarnessCompletionAdmission as s, captureHarnessCompletionRecovery as t };