fix: propagate agent run context for subagent announce

This commit is contained in:
Peter Steinberger
2026-01-19 00:45:03 +00:00
parent 953472bf25
commit 989543c9c3
8 changed files with 157 additions and 3 deletions

View File

@@ -335,6 +335,42 @@ describe("agentCommand", () => {
});
});
it("prefers runContext for embedded routing", async () => {
await withTempHome(async (home) => {
const store = path.join(home, "sessions.json");
mockConfig(home, store);
await agentCommand(
{
message: "hi",
to: "+1555",
channel: "whatsapp",
runContext: { messageChannel: "slack", accountId: "acct-2" },
},
runtime,
);
const callArgs = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0];
expect(callArgs?.messageChannel).toBe("slack");
expect(callArgs?.agentAccountId).toBe("acct-2");
});
});
it("forwards accountId to embedded runs", async () => {
await withTempHome(async (home) => {
const store = path.join(home, "sessions.json");
mockConfig(home, store);
await agentCommand(
{ message: "hi", to: "+1555", accountId: "kev" },
runtime,
);
const callArgs = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0];
expect(callArgs?.agentAccountId).toBe("kev");
});
});
it("logs output when delivery is disabled", async () => {
await withTempHome(async (home) => {
const store = path.join(home, "sessions.json");

View File

@@ -51,6 +51,7 @@ import { applyVerboseOverride } from "../sessions/level-overrides.js";
import { resolveSendPolicy } from "../sessions/send-policy.js";
import { resolveMessageChannel } from "../utils/message-channel.js";
import { deliverAgentCommandResult } from "./agent/delivery.js";
import { resolveAgentRunContext } from "./agent/run-context.js";
import { resolveSession } from "./agent/session.js";
import { updateSessionStoreAfterAgentRun } from "./agent/session-store.js";
import type { AgentCommandOpts } from "./agent/types.js";
@@ -367,8 +368,9 @@ export async function agentCommand(
let fallbackProvider = provider;
let fallbackModel = model;
try {
const runContext = resolveAgentRunContext(opts);
const messageChannel = resolveMessageChannel(
opts.messageChannel,
runContext.messageChannel,
opts.replyChannel ?? opts.channel,
);
const fallbackResult = await runWithModelFallback({
@@ -402,6 +404,11 @@ export async function agentCommand(
sessionId,
sessionKey,
messageChannel,
agentAccountId: runContext.accountId,
currentChannelId: runContext.currentChannelId,
currentThreadTs: runContext.currentThreadTs,
replyToMode: runContext.replyToMode,
hasRepliedRef: runContext.hasRepliedRef,
sessionFile,
workspaceDir,
config: cfg,

View File

@@ -0,0 +1,18 @@
import { normalizeAccountId } from "../../utils/account-id.js";
import { resolveMessageChannel } from "../../utils/message-channel.js";
import type { AgentCommandOpts, AgentRunContext } from "./types.js";
export function resolveAgentRunContext(opts: AgentCommandOpts): AgentRunContext {
const merged: AgentRunContext = opts.runContext ? { ...opts.runContext } : {};
const normalizedChannel = resolveMessageChannel(
merged.messageChannel ?? opts.messageChannel,
opts.replyChannel ?? opts.channel,
);
if (normalizedChannel) merged.messageChannel = normalizedChannel;
const normalizedAccountId = normalizeAccountId(merged.accountId ?? opts.accountId);
if (normalizedAccountId) merged.accountId = normalizedAccountId;
return merged;
}

View File

@@ -7,6 +7,15 @@ export type ImageContent = {
mimeType: string;
};
export type AgentRunContext = {
messageChannel?: string;
accountId?: string;
currentChannelId?: string;
currentThreadTs?: string;
replyToMode?: "off" | "first" | "all";
hasRepliedRef?: { value: boolean };
};
export type AgentCommandOpts = {
message: string;
/** Optional image attachments for multimodal messages. */
@@ -33,6 +42,8 @@ export type AgentCommandOpts = {
channel?: string; // delivery channel (whatsapp|telegram|...)
/** Account ID for multi-account channel routing (e.g., WhatsApp account). */
accountId?: string;
/** Context for embedded run routing (channel/account/thread). */
runContext?: AgentRunContext;
deliveryTargetMode?: ChannelOutboundTargetMode;
bestEffortDeliver?: boolean;
abortSignal?: AbortSignal;