fix: bound subagent completion context

This commit is contained in:
Moeed Ahmed
2026-05-09 15:08:47 +01:00
committed by Ayaan Zaidi
parent 243618e804
commit 3c5e68e80f
4 changed files with 38 additions and 3 deletions

View File

@@ -300,7 +300,7 @@ export const registerTelegramHandlers = ({
if (!isMultiToggleButton(button) || !isSelectedMultiButton(button)) {
return [];
}
return [button.callback_data!.slice(`${MULTI_SELECT_PREFIX}toggle|`.length)];
return [button.callback_data.slice(`${MULTI_SELECT_PREFIX}toggle|`.length)];
}),
);
const updateMultiSelectKeyboard = (
@@ -313,7 +313,7 @@ export const registerTelegramHandlers = ({
if (!isMultiToggleButton(button)) {
return button;
}
const buttonValue = button.callback_data!.slice(`${MULTI_SELECT_PREFIX}toggle|`.length);
const buttonValue = button.callback_data.slice(`${MULTI_SELECT_PREFIX}toggle|`.length);
const baseText = stripMultiSelectPrefix(button.text);
const selected =
action === "clear"

View File

@@ -25,6 +25,8 @@ type AgentTaskCompletionInternalEvent = {
replyInstruction: string;
};
const MAX_CHILD_RESULT_PROMPT_CHARS = 4_000;
export type AgentInternalEvent = AgentTaskCompletionInternalEvent;
export { INTERNAL_RUNTIME_CONTEXT_BEGIN, INTERNAL_RUNTIME_CONTEXT_END };
@@ -41,11 +43,23 @@ function sanitizeMultilineField(value: string, fallback: string): string {
return sanitized || fallback;
}
function truncateChildResultForPrompt(value: string): string {
if (value.length <= MAX_CHILD_RESULT_PROMPT_CHARS) {
return value;
}
return [
value.slice(0, MAX_CHILD_RESULT_PROMPT_CHARS).trimEnd(),
"",
`[child result truncated: ${value.length - MAX_CHILD_RESULT_PROMPT_CHARS} additional characters omitted]`,
].join("\n");
}
function formatChildResultDataBlock(value: string): string {
const safeValue = truncateChildResultForPrompt(value);
return (
wrapPromptDataBlock({
label: "Child result",
text: value,
text: safeValue,
}) || "Child result: (no output)"
);
}

View File

@@ -362,6 +362,26 @@ describe("sanitizeUserFacingText", () => {
);
});
it("bounds large child completion results before injecting internal context", () => {
const internal = formatAgentInternalEventsForPrompt([
{
type: "task_completion",
source: "subagent",
childSessionKey: "agent:main:subagent:test",
childSessionId: "sess_1",
announceType: "subagent task",
taskLabel: "Investigate issue",
status: "ok",
statusLabel: "completed successfully",
result: "x".repeat(6_000),
replyInstruction: "Reply to the user in your own words.",
},
]);
expect(internal).toContain("[child result truncated: 2000 additional characters omitted]");
expect(internal.length).toBeLessThan(5_000);
});
it("does not strip inline delimiter mentions that are not standalone marker lines", () => {
const input = `Note: ${INTERNAL_RUNTIME_CONTEXT_BEGIN} appears inline and should stay.`;
expect(sanitizeUserFacingText(input)).toBe(input);

View File

@@ -1237,6 +1237,7 @@ describe("deliverSubagentAnnouncement completion delivery", () => {
childSessionKey: "agent:openclaw:subagent:child-123",
childSessionId: "child-123",
announceType: "subagent task",
taskLabel: "channel completion smoke",
status: "ok",
statusLabel: "completed successfully",
result: "Raw child result that should stay internal.",