From fca4beac8b1bef69d79cfeb5847d1e95898cc011 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Singh Date: Mon, 17 Aug 2026 09:32:17 -0500 Subject: [PATCH] Tell the agent how to use catalogs and where outputs go --- .../workshop-backend/__tests__/agent-catalog.test.ts | 11 +++++++++++ packages/workshop-backend/src/agent-catalog.ts | 9 ++++++++- packages/workshop-backend/src/overseer.ts | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/workshop-backend/__tests__/agent-catalog.test.ts b/packages/workshop-backend/__tests__/agent-catalog.test.ts index 99038d899..3f6d78341 100644 --- a/packages/workshop-backend/__tests__/agent-catalog.test.ts +++ b/packages/workshop-backend/__tests__/agent-catalog.test.ts @@ -80,6 +80,17 @@ describe("normalizeAgentCatalog", () => { // A resource with no catalog gets just its env line, nothing inlined. expect(message).toContain("- Empty: `env.EMPTY`"); expect(message).not.toContain("- Empty: `env.EMPTY`\n{"); + expect(message).toContain("Check the entries listed above before starting a task"); + expect(message).toContain('A catalog marked `"truncated":true` is partial'); + }); + + it("describes the catalogs only when a resource published entries", () => { + let message = formatAlwaysAvailableResourcesPrompt([ + {title: "Empty", name: "EMPTY", catalog: null}, + ]); + + expect(message).toContain("- Empty: `env.EMPTY`"); + expect(message).not.toContain("Check the entries listed above"); }); }); diff --git a/packages/workshop-backend/src/agent-catalog.ts b/packages/workshop-backend/src/agent-catalog.ts index 084297fd4..f67427b60 100644 --- a/packages/workshop-backend/src/agent-catalog.ts +++ b/packages/workshop-backend/src/agent-catalog.ts @@ -91,9 +91,16 @@ export function formatAlwaysAvailableResourcesPrompt(resources: Array<{ }>): string { let lines = resources.map(resource => `- ${resource.title}: \`env.${resource.name}\`${formatAgentCatalogPrompt(resource.catalog)}`); + // Only describe the catalogs when a resource actually published entries, so a deployment whose + // resources offer none doesn't get told to consult a list that isn't there. + let catalogs = resources.some(resource => resource.catalog?.entries.length) + ? ` Check the entries listed above before starting a task and use a relevant one even when the ` + + `user did not name it. A catalog marked \`"truncated":true\` is partial, so reach what it ` + + `omits through the binding's own search or listing methods.` + : ``; return `The following resources are always available as bindings in your env for use with the ` + `executeCode tool (you don't need to request them):\n${lines.join("\n")}\n` + `When one is relevant, use describeBinding with the binding's name to learn its API before ` + - `using it. If a Gadget's persistent code needs one, wire it into that gadget with ` + + `using it.${catalogs} If a Gadget's persistent code needs one, wire it into that gadget with ` + `setGadgetBinding.`; } diff --git a/packages/workshop-backend/src/overseer.ts b/packages/workshop-backend/src/overseer.ts index e5fed5bb2..b014eaa17 100644 --- a/packages/workshop-backend/src/overseer.ts +++ b/packages/workshop-backend/src/overseer.ts @@ -5834,6 +5834,11 @@ class OverseerImpl implements AgentHooks { `them rather than for an existing one to be repurposed. If the Gadget they are talking ` + `about already *is* one of these, work on that one instead: asking to change an existing ` + `output is not a request for a second one.\n\n` + + `An instruction that names a file path for the result ("save it to notes.md") names the ` + + `output to produce, not a file to write: there is no path to write to. Use the matching ` + + `format below, creating it when the workspace has none, then fill it in through its RPC ` + + `methods, reusing any ready-made layout its code documents rather than positioning ` + + `content yourself.\n\n` + formats.map(format => `* ${format.output.noun} (plural: ${format.output.plural}) — blueprintId: ` + `${format.blueprintId}` + (format.agentHint ? `; ${format.agentHint}` : ``)).join("\n");