Skip to content

Commit 981d9bd

Browse files
committed
fix(sdk): clear stale system-prompt cache options on prompt.set
A later chat.prompt.set() with no options left the previous prompt's providerOptions in locals, so toStreamTextOptions() could still cache a prompt that did not opt in. Always overwrite the slot. Also replaces fixed sleeps in the prompt-caching test with a bounded condition wait.
1 parent 0d5a1d8 commit 981d9bd

2 files changed

Lines changed: 20 additions & 9 deletions

File tree

packages/trigger-sdk/src/v3/ai.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3416,7 +3416,7 @@ const chatPromptKey = locals.create<ChatPromptValue>("chat.prompt");
34163416
* the system block. Stored separately so it works for both the `ResolvedPrompt`
34173417
* and plain-string forms without mutating the prompt object.
34183418
*/
3419-
const chatPromptProviderOptionsKey = locals.create<ProviderMetadata>(
3419+
const chatPromptProviderOptionsKey = locals.create<ProviderMetadata | undefined>(
34203420
"chat.prompt.providerOptions"
34213421
);
34223422

@@ -3460,9 +3460,9 @@ function setChatPrompt(resolved: ResolvedPrompt | string, options?: SetChatPromp
34603460
locals.set(chatPromptKey, resolved);
34613461
}
34623462

3463-
if (options?.providerOptions) {
3464-
locals.set(chatPromptProviderOptionsKey, options.providerOptions);
3465-
}
3463+
// Always overwrite the slot (even with undefined) so a later prompt.set with
3464+
// no options clears a previous prompt's cache opt-in rather than leaking it.
3465+
locals.set(chatPromptProviderOptionsKey, options?.providerOptions);
34663466
}
34673467

34683468
/**

packages/trigger-sdk/test/promptCaching.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ function makeModel(capture: Captured) {
4444
});
4545
}
4646

47+
/** Poll until the mock model captures the system message (bounded), instead of a fixed sleep. */
48+
async function waitForSystemCaptured(capture: Captured, timeoutMs = 1000, intervalMs = 5) {
49+
const startedAt = Date.now();
50+
while (!capture.system) {
51+
if (Date.now() - startedAt > timeoutMs) {
52+
throw new Error("Timed out waiting for system message capture");
53+
}
54+
await new Promise((r) => setTimeout(r, intervalMs));
55+
}
56+
}
57+
4758
const SYSTEM = "You are a helpful assistant for tests.";
4859

4960
describe("chat prompt caching — system providerOptions", () => {
@@ -63,7 +74,7 @@ describe("chat prompt caching — system providerOptions", () => {
6374
const harness = mockChatAgent(agent, { chatId: "pc-default" });
6475
try {
6576
await harness.sendMessage(userMessage("hi"));
66-
await new Promise((r) => setTimeout(r, 20));
77+
await waitForSystemCaptured(cap);
6778
expect(cap.system?.content).toContain("helpful assistant");
6879
expect(cap.system?.providerOptions).toBeUndefined();
6980
} finally {
@@ -92,7 +103,7 @@ describe("chat prompt caching — system providerOptions", () => {
92103
const harness = mockChatAgent(agent, { chatId: "pc-sugar" });
93104
try {
94105
await harness.sendMessage(userMessage("hi"));
95-
await new Promise((r) => setTimeout(r, 20));
106+
await waitForSystemCaptured(cap);
96107
expect(cap.system?.content).toContain("helpful assistant");
97108
expect(cap.system?.providerOptions?.anthropic?.cacheControl).toEqual({ type: "ephemeral" });
98109
} finally {
@@ -123,7 +134,7 @@ describe("chat prompt caching — system providerOptions", () => {
123134
const harness = mockChatAgent(agent, { chatId: "pc-explicit" });
124135
try {
125136
await harness.sendMessage(userMessage("hi"));
126-
await new Promise((r) => setTimeout(r, 20));
137+
await waitForSystemCaptured(cap);
127138
expect(cap.system?.providerOptions?.anthropic?.cacheControl).toEqual({
128139
type: "ephemeral",
129140
ttl: "1h",
@@ -151,7 +162,7 @@ describe("chat prompt caching — system providerOptions", () => {
151162
const harness = mockChatAgent(agent, { chatId: "pc-prompt-set" });
152163
try {
153164
await harness.sendMessage(userMessage("hi"));
154-
await new Promise((r) => setTimeout(r, 20));
165+
await waitForSystemCaptured(cap);
155166
expect(cap.system?.providerOptions?.anthropic?.cacheControl).toEqual({ type: "ephemeral" });
156167
} finally {
157168
await harness.close();
@@ -183,7 +194,7 @@ describe("chat prompt caching — system providerOptions", () => {
183194
const harness = mockChatAgent(agent, { chatId: "pc-precedence" });
184195
try {
185196
await harness.sendMessage(userMessage("hi"));
186-
await new Promise((r) => setTimeout(r, 20));
197+
await waitForSystemCaptured(cap);
187198
// The call-site option wins (ttl: "1h"), not the prompt-set default.
188199
expect(cap.system?.providerOptions?.anthropic?.cacheControl).toEqual({
189200
type: "ephemeral",

0 commit comments

Comments
 (0)