mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-26 15:23:31 +00:00
refactor(agents): unify spawned metadata and extract attachments service
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { listAgentIds } from "../../agents/agent-scope.js";
|
||||
import type { AgentInternalEvent } from "../../agents/internal-events.js";
|
||||
import {
|
||||
normalizeSpawnedRunMetadata,
|
||||
resolveIngressWorkspaceOverrideForSpawnedRun,
|
||||
} from "../../agents/spawned-context.js";
|
||||
import { buildBareSessionResetPrompt } from "../../auto-reply/reply/session-reset-prompt.js";
|
||||
import { agentCommandFromIngress } from "../../commands/agent.js";
|
||||
import { loadConfig } from "../../config/config.js";
|
||||
@@ -165,6 +169,58 @@ async function runSessionResetFromAgent(params: {
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchAgentRunFromGateway(params: {
|
||||
ingressOpts: Parameters<typeof agentCommandFromIngress>[0];
|
||||
runId: string;
|
||||
idempotencyKey: string;
|
||||
respond: GatewayRequestHandlerOptions["respond"];
|
||||
context: GatewayRequestHandlerOptions["context"];
|
||||
}) {
|
||||
void agentCommandFromIngress(params.ingressOpts, defaultRuntime, params.context.deps)
|
||||
.then((result) => {
|
||||
const payload = {
|
||||
runId: params.runId,
|
||||
status: "ok" as const,
|
||||
summary: "completed",
|
||||
result,
|
||||
};
|
||||
setGatewayDedupeEntry({
|
||||
dedupe: params.context.dedupe,
|
||||
key: `agent:${params.idempotencyKey}`,
|
||||
entry: {
|
||||
ts: Date.now(),
|
||||
ok: true,
|
||||
payload,
|
||||
},
|
||||
});
|
||||
// Send a second res frame (same id) so TS clients with expectFinal can wait.
|
||||
// Swift clients will typically treat the first res as the result and ignore this.
|
||||
params.respond(true, payload, undefined, { runId: params.runId });
|
||||
})
|
||||
.catch((err) => {
|
||||
const error = errorShape(ErrorCodes.UNAVAILABLE, String(err));
|
||||
const payload = {
|
||||
runId: params.runId,
|
||||
status: "error" as const,
|
||||
summary: String(err),
|
||||
};
|
||||
setGatewayDedupeEntry({
|
||||
dedupe: params.context.dedupe,
|
||||
key: `agent:${params.idempotencyKey}`,
|
||||
entry: {
|
||||
ts: Date.now(),
|
||||
ok: false,
|
||||
payload,
|
||||
error,
|
||||
},
|
||||
});
|
||||
params.respond(false, payload, error, {
|
||||
runId: params.runId,
|
||||
error: formatForLog(err),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const agentHandlers: GatewayRequestHandlers = {
|
||||
agent: async ({ params, respond, context, client, isWebchatConnect }) => {
|
||||
const p = params;
|
||||
@@ -216,15 +272,17 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
const senderIsOwner = resolveSenderIsOwnerFromClient(client);
|
||||
const cfg = loadConfig();
|
||||
const idem = request.idempotencyKey;
|
||||
const groupIdRaw = typeof request.groupId === "string" ? request.groupId.trim() : "";
|
||||
const groupChannelRaw =
|
||||
typeof request.groupChannel === "string" ? request.groupChannel.trim() : "";
|
||||
const groupSpaceRaw = typeof request.groupSpace === "string" ? request.groupSpace.trim() : "";
|
||||
let resolvedGroupId: string | undefined = groupIdRaw || undefined;
|
||||
let resolvedGroupChannel: string | undefined = groupChannelRaw || undefined;
|
||||
let resolvedGroupSpace: string | undefined = groupSpaceRaw || undefined;
|
||||
let spawnedByValue =
|
||||
typeof request.spawnedBy === "string" ? request.spawnedBy.trim() : undefined;
|
||||
const normalizedSpawned = normalizeSpawnedRunMetadata({
|
||||
spawnedBy: request.spawnedBy,
|
||||
groupId: request.groupId,
|
||||
groupChannel: request.groupChannel,
|
||||
groupSpace: request.groupSpace,
|
||||
workspaceDir: request.workspaceDir,
|
||||
});
|
||||
let resolvedGroupId: string | undefined = normalizedSpawned.groupId;
|
||||
let resolvedGroupChannel: string | undefined = normalizedSpawned.groupChannel;
|
||||
let resolvedGroupSpace: string | undefined = normalizedSpawned.groupSpace;
|
||||
let spawnedByValue = normalizedSpawned.spawnedBy;
|
||||
const inputProvenance = normalizeInputProvenance(request.inputProvenance);
|
||||
const cached = context.dedupe.get(`agent:${idem}`);
|
||||
if (cached) {
|
||||
@@ -613,8 +671,8 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
|
||||
const resolvedThreadId = explicitThreadId ?? deliveryPlan.resolvedThreadId;
|
||||
|
||||
void agentCommandFromIngress(
|
||||
{
|
||||
dispatchAgentRunFromGateway({
|
||||
ingressOpts: {
|
||||
message,
|
||||
images,
|
||||
to: resolvedTo,
|
||||
@@ -647,54 +705,17 @@ export const agentHandlers: GatewayRequestHandlers = {
|
||||
internalEvents: request.internalEvents,
|
||||
inputProvenance,
|
||||
// Internal-only: allow workspace override for spawned subagent runs.
|
||||
workspaceDir: spawnedByValue ? request.workspaceDir : undefined,
|
||||
workspaceDir: resolveIngressWorkspaceOverrideForSpawnedRun({
|
||||
spawnedBy: spawnedByValue,
|
||||
workspaceDir: request.workspaceDir,
|
||||
}),
|
||||
senderIsOwner,
|
||||
},
|
||||
defaultRuntime,
|
||||
context.deps,
|
||||
)
|
||||
.then((result) => {
|
||||
const payload = {
|
||||
runId,
|
||||
status: "ok" as const,
|
||||
summary: "completed",
|
||||
result,
|
||||
};
|
||||
setGatewayDedupeEntry({
|
||||
dedupe: context.dedupe,
|
||||
key: `agent:${idem}`,
|
||||
entry: {
|
||||
ts: Date.now(),
|
||||
ok: true,
|
||||
payload,
|
||||
},
|
||||
});
|
||||
// Send a second res frame (same id) so TS clients with expectFinal can wait.
|
||||
// Swift clients will typically treat the first res as the result and ignore this.
|
||||
respond(true, payload, undefined, { runId });
|
||||
})
|
||||
.catch((err) => {
|
||||
const error = errorShape(ErrorCodes.UNAVAILABLE, String(err));
|
||||
const payload = {
|
||||
runId,
|
||||
status: "error" as const,
|
||||
summary: String(err),
|
||||
};
|
||||
setGatewayDedupeEntry({
|
||||
dedupe: context.dedupe,
|
||||
key: `agent:${idem}`,
|
||||
entry: {
|
||||
ts: Date.now(),
|
||||
ok: false,
|
||||
payload,
|
||||
error,
|
||||
},
|
||||
});
|
||||
respond(false, payload, error, {
|
||||
runId,
|
||||
error: formatForLog(err),
|
||||
});
|
||||
});
|
||||
runId,
|
||||
idempotencyKey: idem,
|
||||
respond,
|
||||
context,
|
||||
});
|
||||
},
|
||||
"agent.identity.get": ({ params, respond }) => {
|
||||
if (!validateAgentIdentityParams(params)) {
|
||||
|
||||
Reference in New Issue
Block a user