| author | |
| committer | |
| log | 255ac27d5200b01c50acef105ab0ec8bb6ab8345 |
| tree | 1ad5ce43615cf436411b23551bd3515779f3764e |
| parent | 24edd55d9459edfa0a2956094b7868102bba5b6f |
| signature | Signed by PGP key B5690EEEBB952194 |
The Claude capabilities probe now asks for usage with skipBehaviors, so it no longer scans every local transcript and misses its 4 s deadline. Takes over #14456.
Co-authored-by: Ashkaan <a@ashkaan.me>2 files changed, 25 insertions(+), 1 deletions(-)
apps/server/src/provider/ClaudeCapabilitiesProbe.test.ts+22| ... | ... | @@ -353,3 +353,25 @@ it.effect("preserves initialized capabilities when optional usage times out", () |
| 353 | 353 | assert.equal(abortSignal?.aborted, true); |
| 354 | 354 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), |
| 355 | 355 | ); |
| 356 | ||
| 357 | it.effect("asks for usage without the local transcript scan", () => | |
| 358 | Effect.gen(function* () { | |
| 359 | let usageOptions: unknown; | |
| 360 | const query = vi.spyOn(ClaudeSdk, "query").mockImplementation( | |
| 361 | () => | |
| 362 | ({ | |
| 363 | initializationResult: async () => ({ | |
| 364 | account: { email: "dev@example.com", subscriptionType: "max", tokenSource: "oauth" }, | |
| 365 | commands: [], | |
| 366 | }), | |
| 367 | usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET: async (options?: unknown) => { | |
| 368 | usageOptions = options; | |
| 369 | return { rate_limits_available: true, rate_limits: null }; | |
| 370 | }, | |
| 371 | }) as unknown as ReturnType<typeof ClaudeSdk.query>, | |
| 372 | ); | |
| 373 | yield* Effect.addFinalizer(() => Effect.sync(() => query.mockRestore())); | |
| 374 | yield* probeClaudeCapabilities(decodeClaudeSettings({ binaryPath: "claude" })); | |
| 375 | assert.deepEqual(usageOptions, { skipBehaviors: true }); | |
| 376 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), | |
| 377 | ); |
apps/server/src/provider/ClaudeProvider.ts+3-1| ... | ... | @@ -367,9 +367,11 @@ const probeClaudeCapabilities = ( |
| 367 | 367 | Effect.flatMap(({ q, init }) => |
| 368 | 368 | Effect.gen(function* () { |
| 369 | 369 | // Usage has its own deadline so a slow optional request cannot discard initialization. |
| 370 | // Only the rate limits are read, so skip the local transcript scan that fills | |
| 371 | // `behaviors`: with a few GB of transcripts it outlasts the deadline. | |
| 370 | 372 | const usageResult = includeUsage |
| 371 | 373 | ? yield* Effect.tryPromise(() => |
| 372 | q.usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET(), | |
| 374 | q.usage_EXPERIMENTAL_MAY_CHANGE_DO_NOT_RELY_ON_THIS_API_YET({ skipBehaviors: true }), | |
| 373 | 375 | ).pipe(Effect.timeout(DEFAULT_TIMEOUT_MS), Effect.result) |
| 374 | 376 | : undefined; |
| 375 | 377 | const usage = |