mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 13:07:39 +00:00
fix(agent): forward resolved outbound session context for delivery
This commit is contained in:
@@ -48,6 +48,7 @@ describe("deliverAgentCommandResult", () => {
|
||||
|
||||
async function runDelivery(params: {
|
||||
opts: Record<string, unknown>;
|
||||
outboundSession?: { key?: string; agentId?: string };
|
||||
sessionEntry?: SessionEntry;
|
||||
runtime?: RuntimeEnv;
|
||||
resultText?: string;
|
||||
@@ -62,6 +63,7 @@ describe("deliverAgentCommandResult", () => {
|
||||
deps,
|
||||
runtime,
|
||||
opts: params.opts as never,
|
||||
outboundSession: params.outboundSession,
|
||||
sessionEntry: params.sessionEntry,
|
||||
result,
|
||||
payloads: result.payloads,
|
||||
@@ -234,6 +236,30 @@ describe("deliverAgentCommandResult", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("uses caller-provided outbound session context when opts.sessionKey is absent", async () => {
|
||||
await runDelivery({
|
||||
opts: {
|
||||
message: "hello",
|
||||
deliver: true,
|
||||
channel: "whatsapp",
|
||||
to: "+15551234567",
|
||||
},
|
||||
outboundSession: {
|
||||
key: "agent:exec:hook:gmail:thread-1",
|
||||
agentId: "exec",
|
||||
},
|
||||
});
|
||||
|
||||
expect(mocks.deliverOutboundPayloads).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
session: expect.objectContaining({
|
||||
key: "agent:exec:hook:gmail:thread-1",
|
||||
agentId: "exec",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("prefixes nested agent outputs with context", async () => {
|
||||
const runtime = createRuntime();
|
||||
await runDelivery({
|
||||
|
||||
@@ -14,6 +14,7 @@ import { setActivePluginRegistry } from "../plugins/runtime.js";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import { createOutboundTestPlugin, createTestRegistry } from "../test-utils/channel-plugins.js";
|
||||
import { agentCommand } from "./agent.js";
|
||||
import * as agentDeliveryModule from "./agent/delivery.js";
|
||||
|
||||
vi.mock("../agents/auth-profiles.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../agents/auth-profiles.js")>();
|
||||
@@ -49,6 +50,7 @@ const runtime: RuntimeEnv = {
|
||||
|
||||
const configSpy = vi.spyOn(configModule, "loadConfig");
|
||||
const runCliAgentSpy = vi.spyOn(cliRunnerModule, "runCliAgent");
|
||||
const deliverAgentCommandResultSpy = vi.spyOn(agentDeliveryModule, "deliverAgentCommandResult");
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(fn, { prefix: "openclaw-agent-" });
|
||||
@@ -230,6 +232,35 @@ describe("agentCommand", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("forwards resolved outbound session context when resuming by sessionId", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const storePattern = path.join(home, "sessions", "{agentId}", "sessions.json");
|
||||
const execStore = path.join(home, "sessions", "exec", "sessions.json");
|
||||
writeSessionStoreSeed(execStore, {
|
||||
"agent:exec:hook:gmail:thread-1": {
|
||||
sessionId: "session-exec-hook",
|
||||
updatedAt: Date.now(),
|
||||
systemSent: true,
|
||||
},
|
||||
});
|
||||
mockConfig(home, storePattern, undefined, undefined, [
|
||||
{ id: "dev" },
|
||||
{ id: "exec", default: true },
|
||||
]);
|
||||
|
||||
await agentCommand({ message: "resume me", sessionId: "session-exec-hook" }, runtime);
|
||||
|
||||
const deliverCall = deliverAgentCommandResultSpy.mock.calls.at(-1)?.[0];
|
||||
expect(deliverCall?.opts.sessionKey).toBeUndefined();
|
||||
expect(deliverCall?.outboundSession).toEqual(
|
||||
expect.objectContaining({
|
||||
key: "agent:exec:hook:gmail:thread-1",
|
||||
agentId: "exec",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("resolves resumed session transcript path from custom session store directory", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
const customStoreDir = path.join(home, "custom-state");
|
||||
|
||||
@@ -59,6 +59,7 @@ import {
|
||||
emitAgentEvent,
|
||||
registerAgentRunContext,
|
||||
} from "../infra/agent-events.js";
|
||||
import { buildOutboundSessionContext } from "../infra/outbound/session-context.js";
|
||||
import { getRemoteSkillEligibility } from "../infra/skills-remote.js";
|
||||
import { normalizeAgentId } from "../routing/session-key.js";
|
||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||
@@ -316,6 +317,11 @@ export async function agentCommand(
|
||||
sessionKey: sessionKey ?? opts.sessionKey?.trim(),
|
||||
config: cfg,
|
||||
});
|
||||
const outboundSession = buildOutboundSessionContext({
|
||||
cfg,
|
||||
agentId: sessionAgentId,
|
||||
sessionKey,
|
||||
});
|
||||
const workspaceDirRaw = resolveAgentWorkspaceDir(cfg, sessionAgentId);
|
||||
const agentDir = resolveAgentDir(cfg, sessionAgentId);
|
||||
const workspace = await ensureAgentWorkspace({
|
||||
@@ -461,6 +467,7 @@ export async function agentCommand(
|
||||
deps,
|
||||
runtime,
|
||||
opts,
|
||||
outboundSession,
|
||||
sessionEntry,
|
||||
result,
|
||||
payloads,
|
||||
@@ -809,6 +816,7 @@ export async function agentCommand(
|
||||
deps,
|
||||
runtime,
|
||||
opts,
|
||||
outboundSession,
|
||||
sessionEntry,
|
||||
result,
|
||||
payloads,
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
normalizeOutboundPayloads,
|
||||
normalizeOutboundPayloadsForJson,
|
||||
} from "../../infra/outbound/payloads.js";
|
||||
import { buildOutboundSessionContext } from "../../infra/outbound/session-context.js";
|
||||
import type { OutboundSessionContext } from "../../infra/outbound/session-context.js";
|
||||
import type { RuntimeEnv } from "../../runtime.js";
|
||||
import { isInternalMessageChannel } from "../../utils/message-channel.js";
|
||||
import type { AgentCommandOpts } from "./types.js";
|
||||
@@ -64,11 +64,12 @@ export async function deliverAgentCommandResult(params: {
|
||||
deps: CliDeps;
|
||||
runtime: RuntimeEnv;
|
||||
opts: AgentCommandOpts;
|
||||
outboundSession: OutboundSessionContext | undefined;
|
||||
sessionEntry: SessionEntry | undefined;
|
||||
result: RunResult;
|
||||
payloads: RunResult["payloads"];
|
||||
}) {
|
||||
const { cfg, deps, runtime, opts, sessionEntry, payloads, result } = params;
|
||||
const { cfg, deps, runtime, opts, outboundSession, sessionEntry, payloads, result } = params;
|
||||
const deliver = opts.deliver === true;
|
||||
const bestEffortDeliver = opts.bestEffortDeliver === true;
|
||||
const turnSourceChannel = opts.runContext?.messageChannel ?? opts.messageChannel;
|
||||
@@ -212,18 +213,13 @@ export async function deliverAgentCommandResult(params: {
|
||||
}
|
||||
if (deliver && deliveryChannel && !isInternalMessageChannel(deliveryChannel)) {
|
||||
if (deliveryTarget) {
|
||||
const deliverySession = buildOutboundSessionContext({
|
||||
cfg,
|
||||
agentId: opts.agentId,
|
||||
sessionKey: opts.sessionKey,
|
||||
});
|
||||
await deliverOutboundPayloads({
|
||||
cfg,
|
||||
channel: deliveryChannel,
|
||||
to: deliveryTarget,
|
||||
accountId: resolvedAccountId,
|
||||
payloads: deliveryPayloads,
|
||||
session: deliverySession,
|
||||
session: outboundSession,
|
||||
replyToId: resolvedReplyToId ?? null,
|
||||
threadId: resolvedThreadTarget ?? null,
|
||||
bestEffort: bestEffortDeliver,
|
||||
|
||||
Reference in New Issue
Block a user