(text: string, context: string)
| 42 | } |
| 43 | |
| 44 | async function tokenizeWithMockModel(text: string, context: string): Promise<number> { |
| 45 | assert(typeof text === "string", `Mock stream ${context} expects string input`); |
| 46 | |
| 47 | // Prefer fast approximate token counting in mock mode. |
| 48 | // We only use the real tokenizer if it's available and responds quickly. |
| 49 | const approximateTokens = approximateTokenCount(text); |
| 50 | |
| 51 | let fallbackUsed = false; |
| 52 | let timeoutId: ReturnType<typeof setTimeout> | undefined; |
| 53 | let tokenizerErrorMessage: string | undefined; |
| 54 | |
| 55 | const fallbackPromise = new Promise<number>((resolve) => { |
| 56 | timeoutId = setTimeout(() => { |
| 57 | fallbackUsed = true; |
| 58 | resolve(approximateTokens); |
| 59 | }, TOKENIZE_TIMEOUT_MS); |
| 60 | }); |
| 61 | |
| 62 | const actualPromise = (async () => { |
| 63 | try { |
| 64 | const tokenizer = await getTokenizerForModel(MOCK_TOKENIZER_MODEL); |
| 65 | assert( |
| 66 | typeof tokenizer.encoding === "string" && tokenizer.encoding.length > 0, |
| 67 | `Tokenizer for ${MOCK_TOKENIZER_MODEL} must expose a non-empty encoding` |
| 68 | ); |
| 69 | const tokens = await tokenizer.countTokens(text); |
| 70 | assert( |
| 71 | Number.isFinite(tokens) && tokens >= 0, |
| 72 | `Tokenizer for ${MOCK_TOKENIZER_MODEL} returned invalid token count` |
| 73 | ); |
| 74 | return tokens; |
| 75 | } catch (error) { |
| 76 | tokenizerErrorMessage = getErrorMessage(error); |
| 77 | return approximateTokens; |
| 78 | } |
| 79 | })(); |
| 80 | |
| 81 | const tokens = await Promise.race([actualPromise, fallbackPromise]); |
| 82 | |
| 83 | if (timeoutId !== undefined) { |
| 84 | clearTimeout(timeoutId); |
| 85 | } |
| 86 | |
| 87 | if (fallbackUsed && !tokenizerFallbackLogged) { |
| 88 | tokenizerFallbackLogged = true; |
| 89 | void actualPromise.then((resolvedTokens) => { |
| 90 | log.debug( |
| 91 | `[MockAiStreamPlayer] Tokenizer fallback used for ${context}; emitted ${approximateTokens}, background tokenizer returned ${resolvedTokens}` |
| 92 | ); |
| 93 | }); |
| 94 | } |
| 95 | |
| 96 | if (tokenizerErrorMessage && !tokenizerUnavailableLogged) { |
| 97 | tokenizerUnavailableLogged = true; |
| 98 | log.debug( |
| 99 | `[MockAiStreamPlayer] Tokenizer unavailable for ${context}; using approximate (${tokenizerErrorMessage})` |
| 100 | ); |
| 101 | } |
no test coverage detected