@juspay/neurolink 9.26.1 → 9.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [9.27.0](https://github.com/juspay/neurolink/compare/v9.26.2...v9.27.0) (2026-03-18)
2
+
3
+ ### Features
4
+
5
+ - **(memory):** add CustomStorageConfig type to Hippocampus integration ([dfcea2b](https://github.com/juspay/neurolink/commit/dfcea2b04834a86812f13c5d85ad3d7b9ab530a7))
6
+
7
+ ## [9.26.2](https://github.com/juspay/neurolink/compare/v9.26.1...v9.26.2) (2026-03-18)
8
+
9
+ ### Bug Fixes
10
+
11
+ - **(providers):** fix Gemini 3.1 native SDK tool calling, streaming, and multimodal on Vertex global endpoint ([b95089a](https://github.com/juspay/neurolink/commit/b95089a5bc900b38678b919a6ae2567c9500ca8b))
12
+
1
13
  ## [9.26.1](https://github.com/juspay/neurolink/compare/v9.26.0...v9.26.1) (2026-03-16)
2
14
 
3
15
  ### Bug Fixes
@@ -90,6 +90,9 @@ const VISION_CAPABILITIES = {
90
90
  "gpt-4-vision-preview",
91
91
  ],
92
92
  "google-ai": [
93
+ // Gemini 3.1 Series (Preview)
94
+ "gemini-3.1-pro-preview",
95
+ "gemini-3.1-flash-lite-preview",
93
96
  // Gemini 3 Series (Preview - November 2025)
94
97
  "gemini-3-pro-preview",
95
98
  "gemini-3-pro-preview-11-2025",
@@ -168,6 +171,9 @@ const VISION_CAPABILITIES = {
168
171
  "gpt-4",
169
172
  ],
170
173
  vertex: [
174
+ // Gemini 3.1 models on Vertex AI (Preview)
175
+ "gemini-3.1-pro-preview",
176
+ "gemini-3.1-flash-lite-preview",
171
177
  // Gemini 3.x models on Vertex AI (Preview)
172
178
  "gemini-3-pro-preview-11-2025",
173
179
  "gemini-3-pro-latest",
@@ -92,6 +92,7 @@ export const MODEL_CONTEXT_WINDOWS = {
92
92
  "gemini-3.1-pro-preview": 1_048_576,
93
93
  "gemini-3.1-flash": 1_048_576,
94
94
  "gemini-3.1-flash-lite": 1_048_576,
95
+ "gemini-3.1-flash-lite-preview": 1_048_576,
95
96
  "gemini-3-pro-preview": 1_048_576,
96
97
  "gemini-3-pro-image-preview": 65_536,
97
98
  "gemini-3-flash-preview": 1_048_576,
@@ -121,6 +122,7 @@ export const MODEL_CONTEXT_WINDOWS = {
121
122
  "gemini-3.1-pro-preview": 1_048_576,
122
123
  "gemini-3.1-flash": 1_048_576,
123
124
  "gemini-3.1-flash-lite": 1_048_576,
125
+ "gemini-3.1-flash-lite-preview": 1_048_576,
124
126
  "gemini-3-pro-preview": 1_048_576,
125
127
  "gemini-3-pro-latest": 1_048_576,
126
128
  "gemini-3-flash-preview": 1_048_576,
@@ -238,6 +238,7 @@ export declare enum VertexModels {
238
238
  GEMINI_3_1_PRO_PREVIEW = "gemini-3.1-pro-preview",
239
239
  GEMINI_3_1_FLASH = "gemini-3.1-flash",
240
240
  GEMINI_3_1_FLASH_LITE = "gemini-3.1-flash-lite",
241
+ GEMINI_3_1_FLASH_LITE_PREVIEW = "gemini-3.1-flash-lite-preview",
241
242
  GEMINI_3_PRO = "gemini-3-pro",
242
243
  GEMINI_3_PRO_PREVIEW_11_2025 = "gemini-3-pro-preview-11-2025",
243
244
  GEMINI_3_PRO_LATEST = "gemini-3-pro-latest",
@@ -265,6 +266,7 @@ export declare enum GoogleAIModels {
265
266
  GEMINI_3_1_PRO_PREVIEW = "gemini-3.1-pro-preview",
266
267
  GEMINI_3_1_FLASH = "gemini-3.1-flash",
267
268
  GEMINI_3_1_FLASH_LITE = "gemini-3.1-flash-lite",
269
+ GEMINI_3_1_FLASH_LITE_PREVIEW = "gemini-3.1-flash-lite-preview",
268
270
  GEMINI_3_PRO_PREVIEW = "gemini-3-pro-preview",
269
271
  GEMINI_3_PRO_IMAGE_PREVIEW = "gemini-3-pro-image-preview",
270
272
  GEMINI_3_FLASH = "gemini-3-flash",
@@ -336,6 +336,7 @@ export var VertexModels;
336
336
  VertexModels["GEMINI_3_1_PRO_PREVIEW"] = "gemini-3.1-pro-preview";
337
337
  VertexModels["GEMINI_3_1_FLASH"] = "gemini-3.1-flash";
338
338
  VertexModels["GEMINI_3_1_FLASH_LITE"] = "gemini-3.1-flash-lite";
339
+ VertexModels["GEMINI_3_1_FLASH_LITE_PREVIEW"] = "gemini-3.1-flash-lite-preview";
339
340
  // Gemini 3 Series (Preview)
340
341
  VertexModels["GEMINI_3_PRO"] = "gemini-3-pro";
341
342
  VertexModels["GEMINI_3_PRO_PREVIEW_11_2025"] = "gemini-3-pro-preview-11-2025";
@@ -369,6 +370,7 @@ export var GoogleAIModels;
369
370
  GoogleAIModels["GEMINI_3_1_PRO_PREVIEW"] = "gemini-3.1-pro-preview";
370
371
  GoogleAIModels["GEMINI_3_1_FLASH"] = "gemini-3.1-flash";
371
372
  GoogleAIModels["GEMINI_3_1_FLASH_LITE"] = "gemini-3.1-flash-lite";
373
+ GoogleAIModels["GEMINI_3_1_FLASH_LITE_PREVIEW"] = "gemini-3.1-flash-lite-preview";
372
374
  // Gemini 3 Series (Preview)
373
375
  GoogleAIModels["GEMINI_3_PRO_PREVIEW"] = "gemini-3-pro-preview";
374
376
  GoogleAIModels["GEMINI_3_PRO_IMAGE_PREVIEW"] = "gemini-3-pro-image-preview";
@@ -90,6 +90,9 @@ const VISION_CAPABILITIES = {
90
90
  "gpt-4-vision-preview",
91
91
  ],
92
92
  "google-ai": [
93
+ // Gemini 3.1 Series (Preview)
94
+ "gemini-3.1-pro-preview",
95
+ "gemini-3.1-flash-lite-preview",
93
96
  // Gemini 3 Series (Preview - November 2025)
94
97
  "gemini-3-pro-preview",
95
98
  "gemini-3-pro-preview-11-2025",
@@ -168,6 +171,9 @@ const VISION_CAPABILITIES = {
168
171
  "gpt-4",
169
172
  ],
170
173
  vertex: [
174
+ // Gemini 3.1 models on Vertex AI (Preview)
175
+ "gemini-3.1-pro-preview",
176
+ "gemini-3.1-flash-lite-preview",
171
177
  // Gemini 3.x models on Vertex AI (Preview)
172
178
  "gemini-3-pro-preview-11-2025",
173
179
  "gemini-3-pro-latest",
@@ -92,6 +92,7 @@ export const MODEL_CONTEXT_WINDOWS = {
92
92
  "gemini-3.1-pro-preview": 1_048_576,
93
93
  "gemini-3.1-flash": 1_048_576,
94
94
  "gemini-3.1-flash-lite": 1_048_576,
95
+ "gemini-3.1-flash-lite-preview": 1_048_576,
95
96
  "gemini-3-pro-preview": 1_048_576,
96
97
  "gemini-3-pro-image-preview": 65_536,
97
98
  "gemini-3-flash-preview": 1_048_576,
@@ -121,6 +122,7 @@ export const MODEL_CONTEXT_WINDOWS = {
121
122
  "gemini-3.1-pro-preview": 1_048_576,
122
123
  "gemini-3.1-flash": 1_048_576,
123
124
  "gemini-3.1-flash-lite": 1_048_576,
125
+ "gemini-3.1-flash-lite-preview": 1_048_576,
124
126
  "gemini-3-pro-preview": 1_048_576,
125
127
  "gemini-3-pro-latest": 1_048_576,
126
128
  "gemini-3-flash-preview": 1_048_576,
@@ -238,6 +238,7 @@ export declare enum VertexModels {
238
238
  GEMINI_3_1_PRO_PREVIEW = "gemini-3.1-pro-preview",
239
239
  GEMINI_3_1_FLASH = "gemini-3.1-flash",
240
240
  GEMINI_3_1_FLASH_LITE = "gemini-3.1-flash-lite",
241
+ GEMINI_3_1_FLASH_LITE_PREVIEW = "gemini-3.1-flash-lite-preview",
241
242
  GEMINI_3_PRO = "gemini-3-pro",
242
243
  GEMINI_3_PRO_PREVIEW_11_2025 = "gemini-3-pro-preview-11-2025",
243
244
  GEMINI_3_PRO_LATEST = "gemini-3-pro-latest",
@@ -265,6 +266,7 @@ export declare enum GoogleAIModels {
265
266
  GEMINI_3_1_PRO_PREVIEW = "gemini-3.1-pro-preview",
266
267
  GEMINI_3_1_FLASH = "gemini-3.1-flash",
267
268
  GEMINI_3_1_FLASH_LITE = "gemini-3.1-flash-lite",
269
+ GEMINI_3_1_FLASH_LITE_PREVIEW = "gemini-3.1-flash-lite-preview",
268
270
  GEMINI_3_PRO_PREVIEW = "gemini-3-pro-preview",
269
271
  GEMINI_3_PRO_IMAGE_PREVIEW = "gemini-3-pro-image-preview",
270
272
  GEMINI_3_FLASH = "gemini-3-flash",
@@ -336,6 +336,7 @@ export var VertexModels;
336
336
  VertexModels["GEMINI_3_1_PRO_PREVIEW"] = "gemini-3.1-pro-preview";
337
337
  VertexModels["GEMINI_3_1_FLASH"] = "gemini-3.1-flash";
338
338
  VertexModels["GEMINI_3_1_FLASH_LITE"] = "gemini-3.1-flash-lite";
339
+ VertexModels["GEMINI_3_1_FLASH_LITE_PREVIEW"] = "gemini-3.1-flash-lite-preview";
339
340
  // Gemini 3 Series (Preview)
340
341
  VertexModels["GEMINI_3_PRO"] = "gemini-3-pro";
341
342
  VertexModels["GEMINI_3_PRO_PREVIEW_11_2025"] = "gemini-3-pro-preview-11-2025";
@@ -369,6 +370,7 @@ export var GoogleAIModels;
369
370
  GoogleAIModels["GEMINI_3_1_PRO_PREVIEW"] = "gemini-3.1-pro-preview";
370
371
  GoogleAIModels["GEMINI_3_1_FLASH"] = "gemini-3.1-flash";
371
372
  GoogleAIModels["GEMINI_3_1_FLASH_LITE"] = "gemini-3.1-flash-lite";
373
+ GoogleAIModels["GEMINI_3_1_FLASH_LITE_PREVIEW"] = "gemini-3.1-flash-lite-preview";
372
374
  // Gemini 3 Series (Preview)
373
375
  GoogleAIModels["GEMINI_3_PRO_PREVIEW"] = "gemini-3-pro-preview";
374
376
  GoogleAIModels["GEMINI_3_PRO_IMAGE_PREVIEW"] = "gemini-3-pro-image-preview";
@@ -1,5 +1,5 @@
1
- import { Hippocampus, type HippocampusConfig } from "@juspay/hippocampus";
2
- export type { HippocampusConfig };
1
+ import { Hippocampus, type HippocampusConfig, type CustomStorageConfig } from "@juspay/hippocampus";
2
+ export type { HippocampusConfig, CustomStorageConfig };
3
3
  export type Memory = HippocampusConfig & {
4
4
  enabled?: boolean;
5
5
  };
@@ -1,4 +1,4 @@
1
- import { Hippocampus } from "@juspay/hippocampus";
1
+ import { Hippocampus, } from "@juspay/hippocampus";
2
2
  import { logger } from "../utils/logger.js";
3
3
  export function initializeHippocampus(config) {
4
4
  try {
@@ -11,7 +11,7 @@ import { logger } from "../utils/logger.js";
11
11
  import { isGemini3Model } from "../utils/modelDetection.js";
12
12
  import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../utils/timeout.js";
13
13
  import { estimateTokens } from "../utils/tokenEstimation.js";
14
- import { buildNativeConfig, buildNativeToolDeclarations, collectStreamChunks, computeMaxSteps, executeNativeToolCalls, extractTextFromParts, handleMaxStepsTermination, pushModelResponseToHistory, sanitizeToolsForGemini, } from "./googleNativeGemini3.js";
14
+ import { buildNativeConfig, buildNativeToolDeclarations, collectStreamChunks, collectStreamChunksIncremental, computeMaxSteps, createTextChannel, executeNativeToolCalls, extractTextFromParts, handleMaxStepsTermination, pushModelResponseToHistory, sanitizeToolsForGemini, } from "./googleNativeGemini3.js";
15
15
  // Google AI Live API types now imported from ../types/providerSpecific.js
16
16
  // Import proper types for multimodal message handling
17
17
  // Create Google GenAI client
@@ -578,107 +578,151 @@ export class GoogleAIStudioProvider extends BaseProvider {
578
578
  }
579
579
  const config = buildNativeConfig(options, toolsConfig);
580
580
  const maxSteps = computeMaxSteps(options.maxSteps);
581
- let finalText = "";
582
- let lastStepText = "";
583
- let totalInputTokens = 0;
584
- let totalOutputTokens = 0;
585
- const allToolCalls = [];
586
- let step = 0;
587
- const failedTools = new Map();
588
581
  // Compose abort signal from user signal + timeout
589
582
  const composedSignal = composeAbortSignals(options.abortSignal, timeoutController?.controller.signal);
590
- // Agentic loop for tool calling
591
- while (step < maxSteps) {
592
- if (composedSignal?.aborted) {
593
- throw composedSignal.reason instanceof Error
594
- ? composedSignal.reason
595
- : new Error("Request aborted");
596
- }
597
- step++;
598
- logger.debug(`[GoogleAIStudio] Native SDK step ${step}/${maxSteps}`);
583
+ // Create a push-based text channel so the caller receives tokens as
584
+ // they arrive from the network rather than after full buffering.
585
+ const channel = createTextChannel();
586
+ // Shared mutable state updated by the background agentic loop.
587
+ const allToolCalls = [];
588
+ // analyticsResolvers lets the background loop settle the analytics
589
+ // promise once token counts are known (after the loop completes).
590
+ let analyticsResolve;
591
+ let analyticsReject;
592
+ const analyticsPromise = new Promise((res, rej) => {
593
+ analyticsResolve = res;
594
+ analyticsReject = rej;
595
+ });
596
+ // Shared metadata object mutated by the background loop so the
597
+ // returned object reflects the final values after stream completion.
598
+ const metadata = {
599
+ streamId: `native-${Date.now()}`,
600
+ startTime,
601
+ responseTime: 0,
602
+ totalToolExecutions: 0,
603
+ };
604
+ // Run the agentic loop in the background without awaiting it here,
605
+ // so we can return the StreamResult (with channel.iterable) immediately.
606
+ const loopPromise = (async () => {
607
+ let lastStepText = "";
608
+ let totalInputTokens = 0;
609
+ let totalOutputTokens = 0;
610
+ let step = 0;
611
+ let completedWithFinalAnswer = false;
612
+ const failedTools = new Map();
599
613
  try {
600
- const stream = await client.models.generateContentStream({
601
- model: modelName,
602
- contents: currentContents,
603
- config,
604
- ...(composedSignal
605
- ? { httpOptions: { signal: composedSignal } }
606
- : {}),
607
- });
608
- const chunkResult = await collectStreamChunks(stream);
609
- totalInputTokens += chunkResult.inputTokens;
610
- totalOutputTokens += chunkResult.outputTokens;
611
- const stepText = extractTextFromParts(chunkResult.rawResponseParts);
612
- // If no function calls, we're done
613
- if (chunkResult.stepFunctionCalls.length === 0) {
614
- finalText = stepText;
615
- break;
614
+ // Agentic loop for tool calling
615
+ while (step < maxSteps) {
616
+ if (composedSignal?.aborted) {
617
+ throw composedSignal.reason instanceof Error
618
+ ? composedSignal.reason
619
+ : new Error("Request aborted");
620
+ }
621
+ step++;
622
+ logger.debug(`[GoogleAIStudio] Native SDK step ${step}/${maxSteps}`);
623
+ try {
624
+ const rawStream = await client.models.generateContentStream({
625
+ model: modelName,
626
+ contents: currentContents,
627
+ config,
628
+ ...(composedSignal
629
+ ? { httpOptions: { signal: composedSignal } }
630
+ : {}),
631
+ });
632
+ // For every step, use incremental collection so text parts
633
+ // are pushed to the channel as they arrive. For intermediate
634
+ // steps (those that produce function calls) we still need the
635
+ // complete rawResponseParts for pushModelResponseToHistory,
636
+ // which collectStreamChunksIncremental provides at stream end.
637
+ const chunkResult = await collectStreamChunksIncremental(rawStream, channel);
638
+ totalInputTokens += chunkResult.inputTokens;
639
+ totalOutputTokens += chunkResult.outputTokens;
640
+ const stepText = extractTextFromParts(chunkResult.rawResponseParts);
641
+ // If no function calls, this was the final step — channel
642
+ // already received all text parts incrementally.
643
+ if (chunkResult.stepFunctionCalls.length === 0) {
644
+ completedWithFinalAnswer = true;
645
+ break;
646
+ }
647
+ lastStepText = stepText;
648
+ // Record tool call events on the span
649
+ for (const fc of chunkResult.stepFunctionCalls) {
650
+ span.addEvent("gen_ai.tool_call", {
651
+ "tool.name": fc.name,
652
+ "tool.step": step,
653
+ });
654
+ }
655
+ logger.debug(`[GoogleAIStudio] Executing ${chunkResult.stepFunctionCalls.length} function calls`);
656
+ // Add model response with ALL parts (including thoughtSignature) to history
657
+ pushModelResponseToHistory(currentContents, chunkResult.rawResponseParts, chunkResult.stepFunctionCalls);
658
+ const functionResponses = await executeNativeToolCalls("[GoogleAIStudio]", chunkResult.stepFunctionCalls, executeMap, failedTools, allToolCalls, { abortSignal: composedSignal });
659
+ // Add function responses to history — the @google/genai SDK
660
+ // only accepts "user" and "model" as valid roles in contents.
661
+ // Function/tool responses must use role: "user" (matching the
662
+ // SDK's own automaticFunctionCalling implementation).
663
+ currentContents.push({
664
+ role: "user",
665
+ parts: functionResponses,
666
+ });
667
+ }
668
+ catch (error) {
669
+ logger.error("[GoogleAIStudio] Native SDK error", error);
670
+ throw this.handleProviderError(error);
671
+ }
616
672
  }
617
- lastStepText = stepText;
618
- // Record tool call events on the span
619
- for (const fc of chunkResult.stepFunctionCalls) {
620
- span.addEvent("gen_ai.tool_call", {
621
- "tool.name": fc.name,
622
- "tool.step": step,
623
- });
673
+ // Handle max-steps termination: if the model was still calling
674
+ // tools when we hit the limit, push a synthetic final message.
675
+ const hitStepLimitWithoutFinalAnswer = step >= maxSteps && !completedWithFinalAnswer;
676
+ if (hitStepLimitWithoutFinalAnswer) {
677
+ const fallback = handleMaxStepsTermination("[GoogleAIStudio]", step, maxSteps, "", // finalText is empty — model didn't stop on its own
678
+ lastStepText);
679
+ if (fallback) {
680
+ channel.push(fallback);
681
+ }
624
682
  }
625
- logger.debug(`[GoogleAIStudio] Executing ${chunkResult.stepFunctionCalls.length} function calls`);
626
- // Add model response with ALL parts (including thoughtSignature) to history
627
- pushModelResponseToHistory(currentContents, chunkResult.rawResponseParts, chunkResult.stepFunctionCalls);
628
- const functionResponses = await executeNativeToolCalls("[GoogleAIStudio]", chunkResult.stepFunctionCalls, executeMap, failedTools, allToolCalls, { abortSignal: composedSignal });
629
- // Add function responses to history the @google/genai SDK
630
- // only accepts "user" and "model" as valid roles in contents.
631
- // Function/tool responses must use role: "user" (matching the
632
- // SDK's own automaticFunctionCalling implementation).
633
- currentContents.push({
634
- role: "user",
635
- parts: functionResponses,
683
+ const responseTime = Date.now() - startTime;
684
+ // Update shared metadata so the returned object reflects final values.
685
+ metadata.responseTime = responseTime;
686
+ metadata.totalToolExecutions = allToolCalls.length;
687
+ // Set token usage and finish reason on the span
688
+ span.setAttribute(ATTR.GEN_AI_INPUT_TOKENS, totalInputTokens);
689
+ span.setAttribute(ATTR.GEN_AI_OUTPUT_TOKENS, totalOutputTokens);
690
+ span.setAttribute(ATTR.GEN_AI_FINISH_REASON, hitStepLimitWithoutFinalAnswer ? "max_steps" : "stop");
691
+ analyticsResolve({
692
+ provider: this.providerName,
693
+ model: modelName,
694
+ tokenUsage: {
695
+ input: totalInputTokens,
696
+ output: totalOutputTokens,
697
+ total: totalInputTokens + totalOutputTokens,
698
+ },
699
+ requestDuration: responseTime,
700
+ timestamp: new Date().toISOString(),
636
701
  });
702
+ channel.close();
637
703
  }
638
- catch (error) {
639
- logger.error("[GoogleAIStudio] Native SDK error", error);
640
- throw this.handleProviderError(error);
704
+ catch (err) {
705
+ channel.error(err);
706
+ analyticsReject(err);
641
707
  }
642
- }
643
- finalText = handleMaxStepsTermination("[GoogleAIStudio]", step, maxSteps, finalText, lastStepText);
644
- const responseTime = Date.now() - startTime;
645
- // Set token usage and finish reason on the span
646
- span.setAttribute(ATTR.GEN_AI_INPUT_TOKENS, totalInputTokens);
647
- span.setAttribute(ATTR.GEN_AI_OUTPUT_TOKENS, totalOutputTokens);
648
- span.setAttribute(ATTR.GEN_AI_FINISH_REASON, step >= maxSteps ? "max_steps" : "stop");
649
- // Create async iterable for streaming result
650
- async function* createTextStream() {
651
- yield { content: finalText };
652
- }
708
+ finally {
709
+ timeoutController?.cleanup();
710
+ }
711
+ })();
712
+ // Suppress unhandled-rejection warnings on loopPromise — errors are
713
+ // forwarded to the channel and will surface when the caller iterates.
714
+ loopPromise.catch(() => undefined);
653
715
  return {
654
- stream: createTextStream(),
716
+ stream: channel.iterable,
655
717
  provider: this.providerName,
656
718
  model: modelName,
657
- toolCalls: allToolCalls.map((tc) => ({
658
- toolName: tc.toolName,
659
- args: tc.args,
660
- })),
661
- analytics: Promise.resolve({
662
- provider: this.providerName,
663
- model: modelName,
664
- tokenUsage: {
665
- input: totalInputTokens,
666
- output: totalOutputTokens,
667
- total: totalInputTokens + totalOutputTokens,
668
- },
669
- requestDuration: responseTime,
670
- timestamp: new Date().toISOString(),
671
- }),
672
- metadata: {
673
- streamId: `native-${Date.now()}`,
674
- startTime,
675
- responseTime,
676
- totalToolExecutions: allToolCalls.length,
677
- },
719
+ toolCalls: allToolCalls,
720
+ analytics: analyticsPromise,
721
+ metadata,
678
722
  };
679
723
  }
680
724
  finally {
681
- timeoutController?.cleanup();
725
+ // Timeout controller cleanup is managed inside the background loop
682
726
  }
683
727
  });
684
728
  }
@@ -709,7 +753,9 @@ export class GoogleAIStudioProvider extends BaseProvider {
709
753
  hasTools: !!options.tools && Object.keys(options.tools).length > 0,
710
754
  });
711
755
  // Build contents from input
712
- const promptText = options.prompt || options.input?.text || "";
756
+ // Prefer input.text over prompt processCSVFilesForNativeSDK enriches
757
+ // input.text with inlined CSV data, so using prompt first would discard it.
758
+ const promptText = options.input?.text || options.prompt || "";
713
759
  const currentContents = [{ role: "user", parts: [{ text: promptText }] }];
714
760
  // Convert tools (merge SDK tools with options.tools)
715
761
  let toolsConfig;
@@ -98,6 +98,49 @@ export declare function collectStreamChunks(stream: AsyncIterable<{
98
98
  functionCalls?: NativeFunctionCall[];
99
99
  [key: string]: unknown;
100
100
  }>): Promise<CollectedChunkResult>;
101
+ /**
102
+ * A push-based text channel that decouples producers (agentic loop) from
103
+ * consumers (the caller's async iterable).
104
+ *
105
+ * The producer calls `push(text)` for each chunk and `close()` / `error(err)`
106
+ * when done. The consumer iterates the `iterable` async generator.
107
+ */
108
+ export type TextChannel = {
109
+ /** Push a text chunk to the consumer. */
110
+ push(text: string): void;
111
+ /** Signal that no more chunks will arrive. */
112
+ close(): void;
113
+ /** Signal that the producer encountered a fatal error. */
114
+ error(err: unknown): void;
115
+ /** Async iterable consumed by the StreamResult. */
116
+ iterable: AsyncIterable<{
117
+ content: string;
118
+ }>;
119
+ };
120
+ /**
121
+ * Create a push-based text channel that bridges a background producer
122
+ * (the agentic tool-calling loop) with an async-iterable consumer.
123
+ *
124
+ * This enables truly incremental streaming: text parts are yielded to the
125
+ * caller as they arrive from the network, rather than being buffered until
126
+ * the model finishes generating.
127
+ */
128
+ export declare function createTextChannel(): TextChannel;
129
+ /**
130
+ * Iterate a single stream step incrementally, pushing text parts to `channel`
131
+ * as they arrive from the network while simultaneously accumulating the full
132
+ * `CollectedChunkResult` needed for history and token accounting.
133
+ *
134
+ * Used for all steps (both intermediate tool-calling steps and the final
135
+ * text-only step). Text parts are pushed to the channel as they arrive,
136
+ * enabling truly incremental streaming. The complete `rawResponseParts`
137
+ * (including thoughtSignature) are still returned at the end for use by
138
+ * `pushModelResponseToHistory`.
139
+ */
140
+ export declare function collectStreamChunksIncremental(stream: AsyncIterable<{
141
+ functionCalls?: NativeFunctionCall[];
142
+ [key: string]: unknown;
143
+ }>, channel: TextChannel): Promise<CollectedChunkResult>;
101
144
  /**
102
145
  * Extract text from raw response parts, filtering out non-text parts
103
146
  * (thoughtSignature, functionCall) to avoid SDK warnings.