Skip to content

Commit 38140c7

Browse files
committed
fix(providers): size prompt-cache gate on the larger of payload.system and request prompt
Gate on max(final payload.system, request.systemPrompt) so caching fires both when the no-messages path blanks payload.system (size via the request prompt) and when prompt-based structured output appends a large schema to payload.system (size via the final system string). Add a test for the schema-appended case. Caught by Cursor Bugbot.
1 parent 3855e04 commit 38140c7

2 files changed

Lines changed: 22 additions & 3 deletions

File tree

apps/sim/providers/anthropic/utils.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ describe('applyAnthropicPromptCache', () => {
5656
expect(tools[0].cache_control).toEqual({ type: 'ephemeral' })
5757
})
5858

59+
it('caches when payload.system is large from appended schema text even if the request prompt is small', () => {
60+
// Prompt-based structured output appends a large schema to payload.system,
61+
// so the cacheable system block is large even though request.systemPrompt is small.
62+
const payload: { system?: string | TextBlockParam[] } = { system: LARGE }
63+
64+
applyAnthropicPromptCache(payload, undefined, SMALL)
65+
66+
expect(Array.isArray(payload.system)).toBe(true)
67+
expect((payload.system as TextBlockParam[])[0].cache_control).toEqual({ type: 'ephemeral' })
68+
})
69+
5970
it('leaves a small, tool-less prefix untouched (no write surcharge on one-shot calls)', () => {
6071
const payload: { system?: string | TextBlockParam[] } = { system: SMALL }
6172

apps/sim/providers/anthropic/utils.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,25 @@ export function applyAnthropicPromptCache(
3434
tools: Tool[] | undefined,
3535
systemPrompt: string | null | undefined
3636
): void {
37+
const payloadSystem = typeof payload.system === 'string' ? payload.system : ''
38+
39+
// Size the gate on the LARGER of the final payload.system (which may include
40+
// appended structured-output schema text) and the original request prompt
41+
// (non-empty even when the no-messages path relocates it out of payload.system).
42+
const gateSystem =
43+
payloadSystem.length >= (systemPrompt?.length ?? 0) ? payloadSystem : systemPrompt
44+
3745
const shouldCache = shouldCacheStaticPrefix({
38-
systemPrompt,
46+
systemPrompt: gateSystem,
3947
hasTools: !!tools?.length,
4048
toolsApproxChars: tools ? JSON.stringify(tools).length : 0,
4149
})
4250
if (!shouldCache) {
4351
return
4452
}
4553

46-
if (typeof payload.system === 'string' && payload.system.length > 0) {
47-
payload.system = [{ type: 'text', text: payload.system, cache_control: { type: 'ephemeral' } }]
54+
if (payloadSystem.length > 0) {
55+
payload.system = [{ type: 'text', text: payloadSystem, cache_control: { type: 'ephemeral' } }]
4856
}
4957

5058
if (tools?.length) {

0 commit comments

Comments
 (0)