fix: agent-only announce path, BB message IDs, sender identity, SSRF allowlist (#23970)

* fix(agents): defer announces until descendant cleanup settles

* fix(bluebubbles): harden message metadata extraction

* feat(contributors): rank by composite score (commits, PRs, LOC, tenure)

* refactor(control-ui): move method guard after path checks to improve request handling

* fix subagent completion announce when only current run is pending

* fix(subagents): keep orchestrator runs active until descendants finish

* fix: prepare PR feedback follow-ups (#23970) (thanks @tyler6204)
This commit is contained in:
Tyler Yust
2026-03-01 22:52:11 -08:00
committed by GitHub
parent cfba64c9db
commit f918b336d1
22 changed files with 814 additions and 155 deletions

View File

@@ -18,6 +18,14 @@ function parseConversationInfoPayload(text: string): Record<string, unknown> {
return JSON.parse(match[1]) as Record<string, unknown>;
}
function parseSenderInfoPayload(text: string): Record<string, unknown> {
const match = text.match(/Sender \(untrusted metadata\):\n```json\n([\s\S]*?)\n```/);
if (!match?.[1]) {
throw new Error("missing sender info json block");
}
return JSON.parse(match[1]) as Record<string, unknown>;
}
describe("buildInboundMetaSystemPrompt", () => {
it("includes session-stable routing fields", () => {
const prompt = buildInboundMetaSystemPrompt({
@@ -147,6 +155,29 @@ describe("buildInboundUserContextPrefix", () => {
expect(conversationInfo["sender"]).toBe("+15551234567");
});
it("prefers SenderName in conversation info sender identity", () => {
const text = buildInboundUserContextPrefix({
ChatType: "group",
SenderName: " Tyler ",
SenderId: " +15551234567 ",
} as TemplateContext);
const conversationInfo = parseConversationInfoPayload(text);
expect(conversationInfo["sender"]).toBe("Tyler");
});
it("includes sender metadata block for direct chats", () => {
const text = buildInboundUserContextPrefix({
ChatType: "direct",
SenderName: "Tyler",
SenderId: "+15551234567",
} as TemplateContext);
const senderInfo = parseSenderInfoPayload(text);
expect(senderInfo["label"]).toBe("Tyler (+15551234567)");
expect(senderInfo["id"]).toBe("+15551234567");
});
it("includes formatted timestamp in conversation info when provided", () => {
const text = buildInboundUserContextPrefix({
ChatType: "group",
@@ -187,7 +218,7 @@ describe("buildInboundUserContextPrefix", () => {
expect(conversationInfo["message_id"]).toBe("msg-123");
});
it("includes message_id_full when it differs from message_id", () => {
it("prefers MessageSid when both MessageSid and MessageSidFull are present", () => {
const text = buildInboundUserContextPrefix({
ChatType: "group",
MessageSid: "short-id",
@@ -196,18 +227,18 @@ describe("buildInboundUserContextPrefix", () => {
const conversationInfo = parseConversationInfoPayload(text);
expect(conversationInfo["message_id"]).toBe("short-id");
expect(conversationInfo["message_id_full"]).toBe("full-provider-message-id");
expect(conversationInfo["message_id_full"]).toBeUndefined();
});
it("omits message_id_full when it matches message_id", () => {
it("falls back to MessageSidFull when MessageSid is missing", () => {
const text = buildInboundUserContextPrefix({
ChatType: "group",
MessageSid: "same-id",
MessageSidFull: "same-id",
MessageSid: " ",
MessageSidFull: "full-provider-message-id",
} as TemplateContext);
const conversationInfo = parseConversationInfoPayload(text);
expect(conversationInfo["message_id"]).toBe("same-id");
expect(conversationInfo["message_id"]).toBe("full-provider-message-id");
expect(conversationInfo["message_id_full"]).toBeUndefined();
});

View File

@@ -88,21 +88,20 @@ export function buildInboundUserContextPrefix(ctx: TemplateContext): string {
const messageId = safeTrim(ctx.MessageSid);
const messageIdFull = safeTrim(ctx.MessageSidFull);
const resolvedMessageId = messageId ?? messageIdFull;
const timestampStr = formatConversationTimestamp(ctx.Timestamp);
const conversationInfo = {
message_id: isDirect ? undefined : messageId,
message_id_full: isDirect
? undefined
: messageIdFull && messageIdFull !== messageId
? messageIdFull
: undefined,
message_id: isDirect ? undefined : resolvedMessageId,
reply_to_id: isDirect ? undefined : safeTrim(ctx.ReplyToId),
sender_id: isDirect ? undefined : safeTrim(ctx.SenderId),
conversation_label: isDirect ? undefined : safeTrim(ctx.ConversationLabel),
sender: isDirect
? undefined
: (safeTrim(ctx.SenderE164) ?? safeTrim(ctx.SenderId) ?? safeTrim(ctx.SenderUsername)),
: (safeTrim(ctx.SenderName) ??
safeTrim(ctx.SenderE164) ??
safeTrim(ctx.SenderId) ??
safeTrim(ctx.SenderUsername)),
timestamp: timestampStr,
group_subject: safeTrim(ctx.GroupSubject),
group_channel: safeTrim(ctx.GroupChannel),
@@ -131,20 +130,20 @@ export function buildInboundUserContextPrefix(ctx: TemplateContext): string {
);
}
const senderInfo = isDirect
? undefined
: {
label: resolveSenderLabel({
name: safeTrim(ctx.SenderName),
username: safeTrim(ctx.SenderUsername),
tag: safeTrim(ctx.SenderTag),
e164: safeTrim(ctx.SenderE164),
}),
name: safeTrim(ctx.SenderName),
username: safeTrim(ctx.SenderUsername),
tag: safeTrim(ctx.SenderTag),
e164: safeTrim(ctx.SenderE164),
};
const senderInfo = {
label: resolveSenderLabel({
name: safeTrim(ctx.SenderName),
username: safeTrim(ctx.SenderUsername),
tag: safeTrim(ctx.SenderTag),
e164: safeTrim(ctx.SenderE164),
id: safeTrim(ctx.SenderId),
}),
id: safeTrim(ctx.SenderId),
name: safeTrim(ctx.SenderName),
username: safeTrim(ctx.SenderUsername),
tag: safeTrim(ctx.SenderTag),
e164: safeTrim(ctx.SenderE164),
};
if (senderInfo?.label) {
blocks.push(
["Sender (untrusted metadata):", "```json", JSON.stringify(senderInfo, null, 2), "```"].join(