openclaw / src /agents /subagents /spawn /subagent-spawn-thread-binding.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
4c76b0d verified
Raw History Blame Contribute Delete
3.67 kB
import { deliveryContextFromConversation } from "../../../channels/route-projection.js";
import {
resolveThreadBindingIntroText,
resolveThreadBindingThreadName,
} from "../../../channels/thread-bindings-messages.js";
import {
resolveThreadBindingIdleTimeoutMsForChannel,
resolveThreadBindingMaxAgeMsForChannel,
} from "../../../channels/thread-bindings-policy.js";
import type { OpenClawConfig } from "../../../config/types.openclaw.js";
import type { DeliveryContext } from "../../../utils/delivery-context.types.js";
import { summarizeSpawnError } from "../../spawn-pipeline.js";
import { prepareSpawnThreadBinding } from "../../spawn-plan.js";
import { getSessionBindingService } from "./subagent-spawn.runtime.js";
import type { SpawnSubagentMode } from "./subagent-spawn.types.js";
export async function bindThreadForSubagentSpawn(params: {
assertActive?: () => void;
cfg: OpenClawConfig;
childSessionKey: string;
agentId: string;
label?: string;
mode: SpawnSubagentMode;
requesterSessionKey?: string;
requester: {
channel?: string;
accountId?: string;
to?: string;
threadId?: string | number;
};
}): Promise<
| { status: "ok"; deliveryOrigin?: DeliveryContext }
| {
status: "error";
error: string;
}
> {
const prepared = prepareSpawnThreadBinding({
cfg: params.cfg,
kind: "subagent",
mode: params.mode,
bindingService: getSessionBindingService(),
requesterSessionKey: params.requesterSessionKey,
channel: params.requester.channel,
accountId: params.requester.accountId,
to: params.requester.to,
threadId: params.requester.threadId,
});
if (!prepared.ok) {
return {
status: "error",
error: prepared.error,
};
}
try {
params.assertActive?.();
const binding = await getSessionBindingService().bind({
targetSessionKey: params.childSessionKey,
targetKind: "subagent",
conversation: {
channel: prepared.binding.channel,
accountId: prepared.binding.accountId,
conversationId: prepared.binding.conversationId,
...(prepared.binding.parentConversationId
? { parentConversationId: prepared.binding.parentConversationId }
: {}),
},
placement: prepared.binding.placement,
metadata: {
threadName: resolveThreadBindingThreadName({
agentId: params.agentId,
label: params.label || params.agentId,
}),
agentId: params.agentId,
label: params.label || undefined,
boundBy: "system",
introText: resolveThreadBindingIntroText({
agentId: params.agentId,
label: params.label || undefined,
idleTimeoutMs: resolveThreadBindingIdleTimeoutMsForChannel({
cfg: params.cfg,
channel: prepared.binding.channel,
accountId: prepared.binding.accountId,
}),
maxAgeMs: resolveThreadBindingMaxAgeMsForChannel({
cfg: params.cfg,
channel: prepared.binding.channel,
accountId: prepared.binding.accountId,
}),
}),
},
});
if (!binding.conversation.conversationId) {
return {
status: "error",
error:
"Unable to create or bind a thread for this subagent session. Session mode is unavailable for this target.",
};
}
const deliveryOrigin = deliveryContextFromConversation(binding.conversation);
return {
status: "ok",
...(deliveryOrigin ? { deliveryOrigin } : {}),
};
} catch (err) {
return {
status: "error",
error: `Thread bind failed: ${summarizeSpawnError(err)}`,
};
}
}