Skip to content

Commit 47e0732

Browse files
fix(router-provider): single-flight ensureModelFetched and earlier call site
Make ensureModelFetched single-flight so concurrent callers share a single in-flight fetch instead of firing duplicates. Move the call site before the cachedStreamingModel snapshot so the model info is accurate from the start of the streaming session, not just for context management. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 101b490 commit 47e0732

3 files changed

Lines changed: 22 additions & 1 deletion

File tree

src/api/providers/__tests__/zoo-gateway.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,16 @@ describe("ZooGatewayHandler", () => {
659659
expect(getModels).not.toHaveBeenCalled()
660660
})
661661

662+
it("deduplicates concurrent calls into a single fetch", async () => {
663+
const handler = new ZooGatewayHandler(mockOptions)
664+
const { getModels } = await import("../fetchers/modelCache")
665+
vitest.mocked(getModels).mockClear()
666+
667+
await Promise.all([handler.ensureModelFetched(), handler.ensureModelFetched()])
668+
669+
expect(getModels).toHaveBeenCalledTimes(1)
670+
})
671+
662672
it("makes getModel return the fetched context window instead of the default", async () => {
663673
const { getModels } = await import("../fetchers/modelCache")
664674
vitest.mocked(getModels).mockResolvedValueOnce({

src/api/providers/router-provider.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,18 @@ export abstract class RouterProvider extends BaseProvider {
6161
return this.getModel()
6262
}
6363

64+
private modelFetchPromise?: Promise<void>
65+
6466
async ensureModelFetched(): Promise<void> {
6567
if (Object.keys(this.models).length === 0) {
66-
await this.fetchModel()
68+
const fetchPromise = (this.modelFetchPromise ??= this.fetchModel().then(() => undefined))
69+
try {
70+
await fetchPromise
71+
} finally {
72+
if (this.modelFetchPromise === fetchPromise) {
73+
this.modelFetchPromise = undefined
74+
}
75+
}
6776
}
6877
}
6978

src/core/task/Task.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2762,6 +2762,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
27622762

27632763
await this.diffViewProvider.reset()
27642764

2765+
await this.api.ensureModelFetched?.()
2766+
27652767
// Cache model info once per API request to avoid repeated calls during streaming
27662768
// This is especially important for tools and background usage collection
27672769
this.cachedStreamingModel = this.api.getModel()

0 commit comments

Comments
 (0)