diff --git a/app/lib/workflows/runAgentStep.ts b/app/lib/workflows/runAgentStep.ts index 33db6714..730b4e40 100644 --- a/app/lib/workflows/runAgentStep.ts +++ b/app/lib/workflows/runAgentStep.ts @@ -36,6 +36,10 @@ export type RunAgentStepInput = { * is added to `experimental_context` right before each model call. */ agentContext: DurableAgentContext; + /** Active artist for the run — surfaced in the agent's system prompt (chat#1837). */ + artistId?: string; + /** Owning account id — surfaced alongside the artist in the system prompt. */ + accountId?: string; /** * Whether a user is present to answer `ask_user_question`. Interactive chat * sets true (default); headless runs (`/api/chat/runs`, `customer-prompt-task`) @@ -135,6 +139,8 @@ export async function runAgentStep(input: RunAgentStepInput): Promise { expect(prompt).toMatch(/never fabricate/i); expect(prompt).toMatch(/sample|estimate|industry average/i); }); + it("emits IMPORTANT CONTEXT VALUES when artistId/accountId are provided", () => { + const prompt = buildAgentSystemPrompt({ + artistId: "ebae4bb9-e38f-4763-b3c8-ff30e99f5d01", + accountId: "fb678396-a68f-4294-ae50-b8cacf9ce77b", + }); + expect(prompt).toMatch(/IMPORTANT CONTEXT VALUES/); + expect(prompt).toContain("artist_account_id: ebae4bb9-e38f-4763-b3c8-ff30e99f5d01"); + expect(prompt).toContain("account_id: fb678396-a68f-4294-ae50-b8cacf9ce77b"); + }); + + it("omits the context section when neither artistId nor accountId is provided", () => { + expect(buildAgentSystemPrompt({})).not.toMatch(/IMPORTANT CONTEXT VALUES/); + }); }); diff --git a/lib/chat/buildAgentSystemPrompt.ts b/lib/chat/buildAgentSystemPrompt.ts index c458b301..46f1e1a4 100644 --- a/lib/chat/buildAgentSystemPrompt.ts +++ b/lib/chat/buildAgentSystemPrompt.ts @@ -26,6 +26,10 @@ export type BuildAgentSystemPromptOptions = { * link prompt + recoup-api skill prompt). */ customInstructions?: string; + /** Active artist for this run — injected so the agent never roster-guesses. */ + artistId?: string; + /** Owning account id (the run's auth identity). */ + accountId?: string; }; /** @@ -55,6 +59,22 @@ export function buildAgentSystemPrompt(options: BuildAgentSystemPromptOptions): parts.push(ENVIRONMENT_SECTION); } + if (options.artistId || options.accountId) { + // Mirrors the interactive chat's getSystemPrompt context block — without + // this, headless agents roster-guess and can land on the org-scoped + // artist list instead of the run's actual artist (recoupable/chat#1837). + const lines = ["# IMPORTANT CONTEXT VALUES (use these exact values in tools)"]; + if (options.artistId) { + lines.push( + `- artist_account_id: ${options.artistId} (the active artist for this run — use for /api/artists/{id}/* and roster operations; do NOT search the roster for it)`, + ); + } + if (options.accountId) { + lines.push(`- account_id: ${options.accountId}`); + } + parts.push(lines.join("\n")); + } + if (options.customInstructions) { parts.push(options.customInstructions); } diff --git a/lib/chat/buildRunAgentInput.ts b/lib/chat/buildRunAgentInput.ts index cc487ddd..c644d400 100644 --- a/lib/chat/buildRunAgentInput.ts +++ b/lib/chat/buildRunAgentInput.ts @@ -11,6 +11,8 @@ export type BuildRunAgentInputParams = { sessionId: string; accountId: string; modelId: string; + /** Active artist for the run — surfaced in the agent's system prompt (chat#1837). */ + artistId?: string; sessionTitle?: string; /** `session.clone_url` — the single source for repo ids + recoup org id. */ cloneUrl: string | null; @@ -44,6 +46,7 @@ export function buildRunAgentInput({ sessionId, accountId, modelId, + artistId, sessionTitle, cloneUrl, sandboxState, @@ -62,6 +65,7 @@ export function buildRunAgentInput({ sessionId, accountId, modelId, + artistId, sessionTitle, interactive, repoOwner: repoIds?.owner, diff --git a/lib/chat/handleChatWorkflowStream.ts b/lib/chat/handleChatWorkflowStream.ts index fab562e1..568e546b 100644 --- a/lib/chat/handleChatWorkflowStream.ts +++ b/lib/chat/handleChatWorkflowStream.ts @@ -128,6 +128,7 @@ export async function handleChatWorkflowStream(request: NextRequest): Promise