graphlit-client 1.0.20250924003 → 1.0.20250924005

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.
@@ -914,6 +914,9 @@ onEvent, onComplete, abortSignal, thinkingConfig) {
914
914
  let toolArgumentTokens = 0;
915
915
  let lastEventTime = 0;
916
916
  const interTokenDelays = [];
917
+ // Thinking content detection state for Google
918
+ let hasEmittedThinkingStart = false;
919
+ let allThinkingContent = "";
917
920
  // Tool calling metrics
918
921
  const toolMetrics = {
919
922
  totalTools: 0,
@@ -984,14 +987,25 @@ onEvent, onComplete, abortSignal, thinkingConfig) {
984
987
  maxOutputTokens: streamConfig.max_tokens,
985
988
  };
986
989
  if (thinkingConfig) {
987
- // Google Gemini Flash 2.5+ supports thinking mode
988
- // The API may use a different parameter name than Anthropic
990
+ // Google Gemini 2.5 supports thinking mode
991
+ // -1 = dynamic thinking (model decides), 0 = disabled, >0 = specific budget
992
+ const budget = thinkingConfig.budget_tokens === 0 ? 0 :
993
+ thinkingConfig.budget_tokens || -1; // Default to dynamic if not specified
994
+ generationConfig.thinkingConfig = {
995
+ thinkingBudget: budget,
996
+ includeThoughts: budget !== 0, // Include thoughts unless explicitly disabled
997
+ };
989
998
  if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
990
- console.log(`🧠 [Google] Extended thinking enabled | Budget: ${thinkingConfig.budget_tokens} tokens`);
999
+ const mode = budget === -1 ? "dynamic" : budget === 0 ? "disabled" : `${budget} tokens`;
1000
+ console.log(`🧠 [Google] Thinking mode: ${mode} | Include thoughts: ${budget !== 0}`);
991
1001
  }
992
- // Note: Google's thinking API implementation may differ from Anthropic
993
- // This is a placeholder for when Google releases their thinking API
994
- // generationConfig.thinking = { enabled: true, maxTokens: thinkingConfig.budget_tokens };
1002
+ }
1003
+ else {
1004
+ // Explicitly disable thinking when not configured
1005
+ generationConfig.thinkingConfig = {
1006
+ thinkingBudget: 0, // Disable thinking by setting budget to 0
1007
+ includeThoughts: false,
1008
+ };
995
1009
  }
996
1010
  const model = googleClient.getGenerativeModel({
997
1011
  model: modelName,
@@ -1004,6 +1018,23 @@ onEvent, onComplete, abortSignal, thinkingConfig) {
1004
1018
  const chat = model.startChat({ history });
1005
1019
  const result = await chat.sendMessageStream(prompt);
1006
1020
  for await (const chunk of result.stream) {
1021
+ // Check for thought parts in streaming chunks first (Google's thinking API)
1022
+ if (thinkingConfig && chunk.candidates?.[0]?.content?.parts) {
1023
+ for (const part of chunk.candidates[0].content.parts) {
1024
+ if (part.thought && part.text) {
1025
+ // Emit thinking content as reasoning events
1026
+ if (!hasEmittedThinkingStart) {
1027
+ onEvent({ type: "reasoning_start", format: "markdown" });
1028
+ hasEmittedThinkingStart = true;
1029
+ allThinkingContent = "";
1030
+ }
1031
+ allThinkingContent += part.text + "\n";
1032
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1033
+ console.log(`[Google] Streaming thought part: ${part.text.length} chars`);
1034
+ }
1035
+ }
1036
+ }
1037
+ }
1007
1038
  const text = chunk.text();
1008
1039
  if (text) {
1009
1040
  fullMessage += text;
@@ -1126,7 +1157,47 @@ onEvent, onComplete, abortSignal, thinkingConfig) {
1126
1157
  console.log(`[Google] Processing final response with ${candidate.content.parts.length} parts`);
1127
1158
  }
1128
1159
  if (candidate?.content?.parts) {
1160
+ let collectedThoughts = "";
1161
+ let hasThoughts = false;
1162
+ // First pass: collect all thought parts from final response
1129
1163
  for (const part of candidate.content.parts) {
1164
+ // Check for thinking/thought parts (Google's thinking API)
1165
+ if (part.thought && thinkingConfig) {
1166
+ hasThoughts = true;
1167
+ collectedThoughts += (part.text || "") + "\n";
1168
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1169
+ console.log(`[Google] Found thought part in final response: ${part.text?.length || 0} chars`);
1170
+ }
1171
+ }
1172
+ }
1173
+ // Emit thinking events if we found thoughts
1174
+ if (hasThoughts && collectedThoughts) {
1175
+ if (!hasEmittedThinkingStart) {
1176
+ onEvent({ type: "reasoning_start", format: "markdown" });
1177
+ }
1178
+ // Combine with any streaming thoughts
1179
+ const finalThoughts = allThinkingContent + collectedThoughts;
1180
+ onEvent({
1181
+ type: "reasoning_end",
1182
+ fullContent: finalThoughts.trim(),
1183
+ });
1184
+ if (process.env.DEBUG_GRAPHLIT_SDK_STREAMING) {
1185
+ console.log(`[Google] Emitted complete thinking: ${finalThoughts.length} chars`);
1186
+ }
1187
+ }
1188
+ else if (hasEmittedThinkingStart && allThinkingContent) {
1189
+ // Close thinking from streaming if no final thoughts
1190
+ onEvent({
1191
+ type: "reasoning_end",
1192
+ fullContent: allThinkingContent.trim(),
1193
+ });
1194
+ }
1195
+ // Second pass: handle regular text parts
1196
+ for (const part of candidate.content.parts) {
1197
+ // Skip thought parts - we already handled them
1198
+ if (part.thought) {
1199
+ continue;
1200
+ }
1130
1201
  // Check for any final text we might have missed
1131
1202
  if (part.text) {
1132
1203
  const finalText = part.text;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphlit-client",
3
- "version": "1.0.20250924003",
3
+ "version": "1.0.20250924005",
4
4
  "description": "Graphlit API Client for TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/client.js",