@@ -51,11 +51,49 @@ const log = createSubsystemLogger("ollama-stream");
5151
5252export const OLLAMA_NATIVE_BASE_URL = OLLAMA_DEFAULT_BASE_URL ;
5353
54+ const OLLAMA_STREAM_COOPERATIVE_YIELD_INTERVAL_MS = 12 ;
55+ const OLLAMA_STREAM_COOPERATIVE_YIELD_MAX_EVENTS = 64 ;
5456const GARBLED_VISIBLE_TEXT_MODEL_RE = / \b (?: g l m | k i m i ) \b / i;
5557const GARBLED_VISIBLE_TEXT_MIN_CHARS = 80 ;
5658const GARBLED_VISIBLE_TEXT_SYMBOL_RE = / [ $ # % & = " ' _ ~ ` ^ | \\ / * + \- [ \] { } ( ) < > : ; , . ! ? ] / gu;
5759const LETTER_OR_DIGIT_RE = / [ \p{ L} \p{ N} ] / gu;
5860
61+ type OllamaStreamCooperativeScheduler = {
62+ afterEvent : ( ) => Promise < void > ;
63+ } ;
64+
65+ function throwIfOllamaStreamAborted ( signal ?: AbortSignal ) : void {
66+ if ( signal ?. aborted ) {
67+ throw new Error ( "Request was aborted" ) ;
68+ }
69+ }
70+
71+ function createOllamaStreamCooperativeScheduler (
72+ signal ?: AbortSignal ,
73+ ) : OllamaStreamCooperativeScheduler {
74+ let lastYieldedAt = Date . now ( ) ;
75+ let eventsSinceYield = 0 ;
76+ return {
77+ async afterEvent ( ) {
78+ throwIfOllamaStreamAborted ( signal ) ;
79+ eventsSinceYield += 1 ;
80+ const now = Date . now ( ) ;
81+ if (
82+ eventsSinceYield < OLLAMA_STREAM_COOPERATIVE_YIELD_MAX_EVENTS &&
83+ now - lastYieldedAt < OLLAMA_STREAM_COOPERATIVE_YIELD_INTERVAL_MS
84+ ) {
85+ return ;
86+ }
87+ eventsSinceYield = 0 ;
88+ lastYieldedAt = now ;
89+ await new Promise < void > ( ( resolve ) => {
90+ setImmediate ( resolve ) ;
91+ } ) ;
92+ throwIfOllamaStreamAborted ( signal ) ;
93+ } ,
94+ } ;
95+ }
96+
5997function countMatches ( text : string , re : RegExp ) : number {
6098 re . lastIndex = 0 ;
6199 return Array . from ( text . matchAll ( re ) ) . length ;
@@ -1169,6 +1207,7 @@ function createRawOllamaStreamFn(
11691207 let pendingFinalVisibleContent : string | undefined ;
11701208 const modelInfo = { api : model . api , provider : model . provider , id : model . id } ;
11711209 const visibleContentSanitizer = createOllamaVisibleContentSanitizer ( model . id ) ;
1210+ const cooperativeScheduler = createOllamaStreamCooperativeScheduler ( options ?. signal ) ;
11721211 let streamStarted = false ;
11731212 let thinkingStarted = false ;
11741213 let thinkingEnded = false ;
@@ -1289,6 +1328,7 @@ function createRawOllamaStreamFn(
12891328 } ;
12901329
12911330 for await ( const chunk of parseNdjsonStream ( reader ) ) {
1331+ throwIfOllamaStreamAborted ( options ?. signal ) ;
12921332 const thinkingDelta = chunk . message ?. thinking ?? chunk . message ?. reasoning ;
12931333 if ( thinkingDelta ) {
12941334 if ( ! streamStarted ) {
@@ -1341,6 +1381,7 @@ function createRawOllamaStreamFn(
13411381 finalResponse = chunk ;
13421382 break ;
13431383 }
1384+ await cooperativeScheduler . afterEvent ( ) ;
13441385 }
13451386
13461387 if ( ! finalResponse ) {
0 commit comments