🗂️ fix: Remove Generated Code Files From Prompt Context (#13037)

This commit is contained in:
Danny Avila 2026-05-09 11:38:53 -04:00 committed by GitHub
parent c7a4e6d418
commit ac3600cdd7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 72 additions and 36 deletions

View file

@ -709,6 +709,41 @@ async function getSessionInfo(ref) {
} }
} }
const getPreviewContextSuffix = (file) => {
if (file.status === 'pending') {
return ' (preview not yet generated)';
}
if (file.status !== 'failed') {
return '';
}
return file.previewError
? ` (preview unavailable: ${file.previewError})`
: ' (preview unavailable)';
};
const getVisibleCodeFileContextLine = (file, agentResourceIds) => {
if (file.context === FileContext.execute_code) {
return '';
}
const fileSuffix = agentResourceIds.has(file.file_id) ? '' : ' (attached by user)';
return `\n\t- /mnt/data/${file.filename}${fileSuffix}${getPreviewContextSuffix(file)}`;
};
const appendVisibleCodeFileContext = (toolContext, contextLine) => {
if (!contextLine) {
return toolContext;
}
if (toolContext) {
return `${toolContext}${contextLine}`;
}
return `- Note: The following files are available in the "${Tools.execute_code}" tool environment:${contextLine}`;
};
/** /**
* *
* @param {Object} options * @param {Object} options
@ -797,34 +832,10 @@ const primeFiles = async (options) => {
* tenant prefix from auth context). * tenant prefix from auth context).
*/ */
const pushFile = (overrideSessionId, overrideId) => { const pushFile = (overrideSessionId, overrideId) => {
if (!toolContext) { toolContext = appendVisibleCodeFileContext(
toolContext = `- Note: The following files are available in the "${Tools.execute_code}" tool environment:`; toolContext,
} getVisibleCodeFileContextLine(file, agentResourceIds),
);
let fileSuffix = '';
if (!agentResourceIds.has(file.file_id)) {
fileSuffix =
file.context === FileContext.execute_code
? ' (from previous code execution)'
: ' (attached by user)';
}
/* Surface the preview lifecycle so the LLM knows when a
* prior-turn artifact's rich preview didn't materialize. The
* file blob is always available (`processCodeOutput` persists
* it before returning), so the model can still tell the user
* "you can download it" even when the preview never resolved.
* Absent status means legacy or non-office render normally. */
let previewSuffix = '';
if (file.status === 'pending') {
previewSuffix = ' (preview not yet generated)';
} else if (file.status === 'failed') {
previewSuffix = file.previewError
? ` (preview unavailable: ${file.previewError})`
: ' (preview unavailable)';
}
toolContext += `\n\t- /mnt/data/${file.filename}${fileSuffix}${previewSuffix}`;
/* `id` is the storage file_id (drives codeapi's upload-key /* `id` is the storage file_id (drives codeapi's upload-key
* existence check), `resource_id` is the entity that owns * existence check), `resource_id` is the entity that owns
* the storage session (drives sessionKey re-derivation). For * the storage session (drives sessionKey re-derivation). For

View file

@ -1770,13 +1770,11 @@ describe('Code Process', () => {
}); });
}); });
describe('primeFiles toolContext surfaces preview status to the LLM', () => { describe('primeFiles toolContext for model-visible code files', () => {
/* When a prior-turn code-execution file's HTML preview never resolved /* User-visible code-env input files keep their `/mnt/data` context and
* (still pending, or failed), the agent context for this turn must * preview lifecycle hints. Prior-turn generated artifacts are still
* carry that signal so the model can tell the user "you can still * primed into the sandbox, but no longer repeated in model-visible
* download it, but the preview isn't available." Otherwise the model * instructions every turn. */
* would refer to the file as if everything is fine and the user gets
* a confusing UI mismatch. */
const { getStrategyFunctions } = require('~/server/services/Files/strategies'); const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { getFiles } = require('~/models'); const { getFiles } = require('~/models');
@ -1788,7 +1786,7 @@ describe('Code Process', () => {
filename: `data-${overrides.status ?? 'ready'}.xlsx`, filename: `data-${overrides.status ?? 'ready'}.xlsx`,
filepath: `/uploads/${overrides.status ?? 'ready'}.xlsx`, filepath: `/uploads/${overrides.status ?? 'ready'}.xlsx`,
source: 'local', source: 'local',
context: 'execute_code', context: FileContext.message_attachment,
metadata: { metadata: {
codeEnvRef: { codeEnvRef: {
kind: 'user', kind: 'user',
@ -1811,6 +1809,33 @@ describe('Code Process', () => {
filterFilesByAgentAccess.mockImplementation(({ files }) => Promise.resolve(files)); filterFilesByAgentAccess.mockImplementation(({ files }) => Promise.resolve(files));
} }
it('does not include generated code files in model-visible toolContext', async () => {
setupSessionInfoOk();
getFiles.mockResolvedValue([
makeFile({
context: FileContext.execute_code,
filename: 'generated.html',
}),
]);
const result = await primeFiles({
req: { user: { id: 'user-123', role: 'USER' } },
tool_resources: { execute_code: { file_ids: ['fid-ready'], files: [] } },
agentId: 'agent-id',
});
expect(result.toolContext).toBe('');
expect(result.files).toEqual([
{
id: 'CURRENT_ID',
resource_id: 'user-123',
storage_session_id: 'CURRENT_SESSION',
name: 'generated.html',
kind: 'user',
},
]);
});
it('annotates a pending file with "(preview not yet generated)"', async () => { it('annotates a pending file with "(preview not yet generated)"', async () => {
setupSessionInfoOk(); setupSessionInfoOk();
getFiles.mockResolvedValue([makeFile({ status: 'pending' })]); getFiles.mockResolvedValue([makeFile({ status: 'pending' })]);