mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-08 00:02:27 +00:00
fix(ai-chat): stop echoing app draft value in global chat write tool results (#9658)
finishAppDraftWrite returned `item: result.item`, whose `value` is the entire app draft (every frontend file body and inline runnable). Each write_app_file / patch_app_file / write_app_runnable therefore re-sent the whole app back to the model; on a large app a few edits overflow the 200k context window. This restores #9530 (which removed the echo) — the DB-backed-draft refactor (#9601) reintroduced it by routing all app writes through this shared helper with `item:` re-added. Write results now return only `{ success, message }`, matching the flow write tools. Adds a regression test asserting the value is not echoed. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3f5f211a22
commit
2fed808b9e
@@ -783,6 +783,40 @@ describe('global AI tools', () => {
|
||||
expect(getBackendDraft('raw_app', 'u/admin/live_app', { workspace: WORKSPACE })).toBeUndefined()
|
||||
})
|
||||
|
||||
it('does not echo the app value back to the model on write', async () => {
|
||||
const sentinel = 'SENTINEL_DO_NOT_ECHO_DEADBEEF'
|
||||
seedBackendDraft(
|
||||
'raw_app',
|
||||
'',
|
||||
{
|
||||
summary: 'Echo check',
|
||||
files: { '/src/App.tsx': `export default function App() { return '${sentinel}' }` },
|
||||
runnables: {},
|
||||
data: { tables: [] }
|
||||
},
|
||||
{ workspace: WORKSPACE }
|
||||
)
|
||||
UserDraft.setLiveEditorDraft({
|
||||
workspace: WORKSPACE,
|
||||
itemKind: 'raw_app',
|
||||
storagePath: '',
|
||||
effectivePath: 'u/admin/echo_app'
|
||||
})
|
||||
|
||||
const raw = await callGlobalTool('write_app_file', {
|
||||
path: 'u/admin/echo_app',
|
||||
file_path: '/src/New.tsx',
|
||||
content: 'export default function New() { return null }'
|
||||
})
|
||||
|
||||
const parsed = JSON.parse(raw)
|
||||
expect(parsed.success).toBe(true)
|
||||
expect(parsed.item).toBeUndefined()
|
||||
// Neither the pre-existing file body nor the just-written one is resent.
|
||||
expect(raw).not.toContain(sentinel)
|
||||
expect(raw).not.toContain('function New')
|
||||
})
|
||||
|
||||
it('discards a draft without deleting the workspace item', async () => {
|
||||
await callGlobalTool('write_script', {
|
||||
path: 'f/scripts/discard-me',
|
||||
|
||||
@@ -2399,13 +2399,13 @@ function draftWriteFailure(result: DraftPersistResult, ctx: WriteDraftCtx): stri
|
||||
function finishAppDraftWrite(
|
||||
result: DraftPersistResult,
|
||||
ctx: WriteDraftCtx,
|
||||
onSaved: (item: WorkspaceItem) => { content: string; message: string }
|
||||
onSaved: () => { content: string; message: string }
|
||||
): string {
|
||||
const failure = draftWriteFailure(result, ctx)
|
||||
if (failure) return failure
|
||||
const { content, message } = onSaved(result.item)
|
||||
const { content, message } = onSaved()
|
||||
ctx.toolCallbacks.setToolStatus(ctx.toolId, { content, result: 'Saved as draft' })
|
||||
return JSON.stringify({ success: true, message, item: result.item }, null, 2)
|
||||
return JSON.stringify({ success: true, message }, null, 2)
|
||||
}
|
||||
|
||||
function finishDraftWrite(
|
||||
|
||||
Reference in New Issue
Block a user