Skip to content

Commit e242bb5

Browse files
Theaxiomclaude
andcommitted
fix(mcp): strengthen chat-uploads teaching to forbid soliciting file content
Real product bug: with the chat-uploads capability active, a user who attached a document and typed "summarize this document" got the response "please provide the document's content or a URL." Zaru's default agentic-mode pattern (solicit content/URL) was winning because the existing CHAT_UPLOADS_TEACHING was about pass-through mechanics, not the higher-level rule "the user already attached the file; the platform staged it; do not ask them for it again." Rewrote the teaching block to: - Make explicit that uploaded files are staged and surfaced via attachments[] automatically. - Forbid asking the user to provide content / paste text / share URL when their intent implies an attached file. - Direct Zaru to read attachments via aegis.attachment.read inside the dispatched agent. - Forbid paraphrasing the user's intent in ways that lose the attachment signal at agent generation time. - Preserve the existing pass-through rules. Tests assert the new phrases appear when capability is active and are absent when it is not. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent f603cae commit e242bb5

2 files changed

Lines changed: 57 additions & 5 deletions

File tree

zaru-mcp-server/src/prompts/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,14 +462,21 @@ const PROMPTS: Record<string, string> = {
462462

463463
const CHAT_UPLOADS_TEACHING = `
464464
465-
# CHAT ATTACHMENTS — PASS-THROUGH RULE
465+
# CHAT ATTACHMENTS — UPLOADED FILES ARE HANDLED FOR YOU
466466
467-
The user may attach files to their messages. When attachments are present, your tool call inputs will include an \`attachments\` field — an array of \`{volume_id, path, name, mime_type, size}\` references that point at files staged in a sandbox-readable volume. Zaru handles file references deterministically; you do not need to construct, paraphrase, rename, or modify them.
467+
The user can attach files (documents, images, etc.) directly to their messages via the chat UI. When they do, the platform stages those files server-side and surfaces them on every dispatch as an \`attachments\` field — an array of \`{volume_id, path, name, mime_type, size}\` references pointing at sandbox-readable volume entries. Zaru handles these references deterministically; you do not need to construct, paraphrase, rename, or modify them.
468468
469+
CRITICAL — NEVER ask the user to "provide the document's content," "paste the text," or "share a URL" when their request implies a file was attached. Phrases that imply an attachment include "summarize this document," "what's in this file," "analyze the attached PDF," "translate this report," and similar. The user already attached the file; the platform already staged it; soliciting content or a URL is the wrong default for this UX.
470+
471+
- If the dispatch's \`attachments\` array is non-empty, the file is already staged. Generate or dispatch an agent that reads the file via the \`aegis.attachment.read({volume_id, path})\` tool from inside its sandbox — do NOT route through web-fetch, fs.read, or asking the user to re-supply content.
472+
- If the user's intent implies a file but \`attachments\` is empty on your dispatch input, ask them whether they meant to attach a file. Do NOT default to soliciting a URL or pasted text — that's the wrong fallback.
473+
474+
PASS-THROUGH RULES:
469475
- When dispatching an agent (\`aegis.task.execute\`, \`aegis.agent.generate\`) or running a workflow, pass the same \`attachments\` array through verbatim on the call. The downstream agent or workflow needs the references to read the files inside its sandbox.
470-
- Do NOT read, summarise, or describe the file contents yourself before dispatching — the 100monkeys read the files in their sandbox. You just hand off the references.
476+
- Do NOT read, summarise, or describe the file contents yourself before dispatching — the 100monkeys read the files in their sandbox via \`aegis.attachment.read\`. You just hand off the references.
471477
- Do NOT fabricate \`attachments\` entries. Only forward what the client supplied.
472-
- If the user's intent involves processing an attached file, ensure every agent or workflow you dispatch receives the same \`attachments\` array on its input.`;
478+
- If the user's intent involves processing an attached file, ensure every agent or workflow you dispatch receives the same \`attachments\` array on its input.
479+
- Do NOT paraphrase the user's intent in ways that lose the attachment signal. A request "summarize this document" with an attached PDF must reach \`aegis.agent.generate\` as something like "summarize the attached document" with the \`attachments\` array forwarded — NOT paraphrased into "create a generic text-input agent that summarizes documents."`;
473480

474481
/** Modes that accept and forward `attachments` when the chat-uploads capability is active. */
475482
const CHAT_UPLOADS_MODES = new Set(["agentic", "workflow"]);

zaru-mcp-server/test/prompts.test.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ test("getZaruInit('nonexistent') returns null", () => {
9494
// workflow modes (ADR-113).
9595
// ---------------------------------------------------------------------------
9696

97-
const CHAT_UPLOADS_MARKER = "CHAT ATTACHMENTS — PASS-THROUGH RULE";
97+
const CHAT_UPLOADS_MARKER =
98+
"CHAT ATTACHMENTS — UPLOADED FILES ARE HANDLED FOR YOU";
99+
const CHAT_UPLOADS_NEVER_ASK_MARKER = "NEVER ask the user";
100+
const CHAT_UPLOADS_TOOL_MARKER = "aegis.attachment.read";
98101

99102
test("getZaruInit('agentic') with the 'chat-uploads' capability augments the system prompt with attachment teaching", () => {
100103
const withCap = getZaruInit("agentic", new Set(["chat-uploads"]));
@@ -175,3 +178,45 @@ test("getZaruInit('operator') with 'chat-uploads' does NOT inject attachment tea
175178
assert.notEqual(result, null);
176179
assert.ok(!result!.system_prompt.includes(CHAT_UPLOADS_MARKER));
177180
});
181+
182+
// ---------------------------------------------------------------------------
183+
// chat-uploads teaching content — explicit "do not solicit" + tool-name rules
184+
// ---------------------------------------------------------------------------
185+
186+
test("getZaruInit('agentic') with 'chat-uploads' forbids soliciting file content from the user", () => {
187+
const result = getZaruInit("agentic", new Set(["chat-uploads"]));
188+
assert.notEqual(result, null);
189+
assert.ok(
190+
result!.system_prompt.includes(CHAT_UPLOADS_NEVER_ASK_MARKER),
191+
"expected the prompt to contain a 'NEVER ask the user' rule preventing solicitation of content / URLs when a file was attached",
192+
);
193+
});
194+
195+
test("getZaruInit('agentic') with 'chat-uploads' names aegis.attachment.read as the read tool", () => {
196+
const result = getZaruInit("agentic", new Set(["chat-uploads"]));
197+
assert.notEqual(result, null);
198+
assert.ok(
199+
result!.system_prompt.includes(CHAT_UPLOADS_TOOL_MARKER),
200+
"expected the prompt to mention `aegis.attachment.read` so dispatched agents know which tool to use",
201+
);
202+
});
203+
204+
test("getZaruInit('workflow') with 'chat-uploads' includes both the 'never ask' rule and aegis.attachment.read", () => {
205+
const result = getZaruInit("workflow", new Set(["chat-uploads"]));
206+
assert.notEqual(result, null);
207+
assert.ok(result!.system_prompt.includes(CHAT_UPLOADS_NEVER_ASK_MARKER));
208+
assert.ok(result!.system_prompt.includes(CHAT_UPLOADS_TOOL_MARKER));
209+
});
210+
211+
test("getZaruInit('agentic') WITHOUT 'chat-uploads' does NOT contain the new teaching phrases (capability still gates them)", () => {
212+
const result = getZaruInit("agentic");
213+
assert.notEqual(result, null);
214+
assert.ok(
215+
!result!.system_prompt.includes(CHAT_UPLOADS_NEVER_ASK_MARKER),
216+
"the 'NEVER ask the user' phrase must not leak into the base agentic prompt",
217+
);
218+
assert.ok(
219+
!result!.system_prompt.includes(CHAT_UPLOADS_TOOL_MARKER),
220+
"the aegis.attachment.read mention must not leak into the base agentic prompt",
221+
);
222+
});

0 commit comments

Comments
 (0)