diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
 # Changelog for langchain-hs-gemini
 
+## 0.0.6.2 - 2026-11-14
+
+> **Note**: `0.0.6.1` was skipped globally after `langchain-hs-ollama-v0.0.6.1`.
+
+- Added incremental tool-call emission during SSE streaming in `Langchain.Provider.Gemini` (`ChatModel.stream`).
+- Consolidates Interactions v1 Servant bindings (`Gemini.Client.*`) and `Langchain.Embeddings.Gemini` under aligned `0.0.6.2`.
+- Updated `langchain-hs-core` dependency bound to `>= 0.0.6.2 && < 0.0.7`.
+
 ## 0.0.6.0 - 2026-10-02
 
 - Initial release. Split from the monolithic `langchain-hs` package.
diff --git a/langchain-hs-gemini.cabal b/langchain-hs-gemini.cabal
--- a/langchain-hs-gemini.cabal
+++ b/langchain-hs-gemini.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           langchain-hs-gemini
-version:        0.0.6.0
+version:        0.0.6.2
 synopsis:       Google Gemini provider for langchain-hs
 description:    Google Gemini ChatModel provider for langchain-hs. Supports multi-modal content, streaming via Server-Sent Events, and function calling. Does not depend on OpenAI or Ollama packages.
 category:       AI
@@ -51,7 +51,7 @@
     , http-client ==0.7.*
     , http-client-tls >=0.3 && <0.5
     , http-conduit ==2.*
-    , langchain-hs-core ==0.0.6.*
+    , langchain-hs-core >=0.0.6.2 && <0.0.7
     , mtl >=2.2 && <2.4
     , resourcet >=1.2 && <1.4
     , servant >=0.19 && <0.21
diff --git a/src/Langchain/Provider/Gemini.hs b/src/Langchain/Provider/Gemini.hs
--- a/src/Langchain/Provider/Gemini.hs
+++ b/src/Langchain/Provider/Gemini.hs
@@ -29,14 +29,16 @@
   ) where
 
 import Control.Applicative ((<|>))
+import Control.Monad (forM_)
 import Control.Monad.Except (throwError)
 import Control.Monad.IO.Class (liftIO)
-import Data.Aeson (FromJSON, ToJSON, decodeStrict, object, toJSON, (.=))
+import Data.Aeson (FromJSON, ToJSON, decodeStrict, eitherDecodeStrict, object, toJSON, (.=))
 import Data.Conduit (await, yield, (.|))
 import qualified Data.List as List
 import qualified Data.List.NonEmpty as NonEmpty
 import qualified Data.Map.Strict as Map
 import Data.Maybe (fromMaybe)
+import qualified Data.Set as Set
 import Data.Text (Text)
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as TE
@@ -270,31 +272,101 @@
       Nothing -> newGeminiClientEnv (apiKey provider)
     let req = buildCreateRequest provider msgs mbConfig
 
-    (accumulated, mbCompletedInter) <-
-      streamGeminiInteraction env req .| consumeStream rId "" Nothing
+    (accumulated, pendingCalls, emittedCalls, thoughtSigs, mbCompletedInter) <-
+      streamGeminiInteraction env req .| consumeStream rId "" Map.empty [] [] Nothing
 
+    -- Finalize any tool calls whose step.start was not followed by step.stop
+    remainingCalls <- traverse finalizePendingCall (Map.elems pendingCalls)
+    forM_ remainingCalls $ \tc ->
+      yield $ LLMChunk rId "" (Just tc)
+
+    let allEmitted = reverse emittedCalls ++ remainingCalls
     case mbCompletedInter of
       Just completedInter -> do
         let finalMsg = interactionToMessage completedInter
             usage = toTokenUsage (interactionUsage completedInter)
+            alreadyEmittedIds = Set.fromList [(toolCallId tc, toolCallName tc) | tc <- allEmitted]
+            missingChunkCalls =
+              filter
+                (\tc -> not $ Set.member (toolCallId tc, toolCallName tc) alreadyEmittedIds)
+                (fromMaybe [] (messageToolCalls finalMsg))
+        forM_ missingChunkCalls $ \tc ->
+          yield $ LLMChunk rId "" (Just tc)
         yield $ LLMEnd rId finalMsg usage
       Nothing -> do
-        let finalMsg = assistantMessage accumulated
+        let base = assistantMessage accumulated
+            withCalls =
+              if null allEmitted
+                then base
+                else base {messageToolCalls = Just allEmitted}
+            sigs = reverse thoughtSigs
+            finalMsg =
+              if null sigs
+                then withCalls
+                else
+                  withCalls
+                    { messageMetadata =
+                        Map.insert
+                          "langchain.gemini.thoughtSignatures"
+                          (toJSON sigs)
+                          (messageMetadata withCalls)
+                    }
         yield $ LLMEnd rId finalMsg Nothing
     where
-      consumeStream rId acc mbCompleted =
+      finalizePendingCall (cid, cname, initArgs, argText)
+        | T.null (T.strip argText) =
+            pure
+              ToolCall
+                { toolCallId = cid
+                , toolCallType = "function"
+                , toolCallName = cname
+                , toolCallArguments = initArgs
+                }
+        | otherwise =
+            case eitherDecodeStrict (TE.encodeUtf8 argText) of
+              Left err ->
+                throwError $ llmError ("Invalid JSON arguments in Gemini tool call: " <> T.pack err) Nothing Nothing
+              Right parsedArgs ->
+                pure
+                  ToolCall
+                    { toolCallId = cid
+                    , toolCallType = "function"
+                    , toolCallName = cname
+                    , toolCallArguments = parsedArgs
+                    }
+
+      consumeStream rId acc pending emitted sigs mbCompleted =
         await >>= \case
-          Nothing -> pure (acc, mbCompleted)
+          Nothing -> pure (acc, pending, emitted, sigs, mbCompleted)
+          Just (SseStepStart idx FunctionCallStep {..}) ->
+            let pending' = Map.insert idx (callId, callName, callArguments, "") pending
+             in consumeStream rId acc pending' emitted sigs mbCompleted
           Just (SseStepDelta _ (TextDelta txt)) -> do
             yield $ LLMChunk rId txt Nothing
-            consumeStream rId (acc <> txt) mbCompleted
+            consumeStream rId (acc <> txt) pending emitted sigs mbCompleted
+          Just (SseStepDelta idx (ArgumentsDelta argDelta)) ->
+            let pending' =
+                  Map.adjust
+                    (\(cid, cname, initArgs, argTxt) -> (cid, cname, initArgs, argTxt <> argDelta))
+                    idx
+                    pending
+             in consumeStream rId acc pending' emitted sigs mbCompleted
+          Just (SseStepDelta _ (ThoughtSignatureDelta sig)) ->
+            consumeStream rId acc pending emitted (sig : sigs) mbCompleted
+          Just (SseStepStop idx) ->
+            case Map.lookup idx pending of
+              Nothing -> consumeStream rId acc pending emitted sigs mbCompleted
+              Just entry -> do
+                tc <- finalizePendingCall entry
+                yield $ LLMChunk rId "" (Just tc)
+                consumeStream rId acc (Map.delete idx pending) (tc : emitted) sigs mbCompleted
           Just (SseInteractionCompleted inter) ->
-            consumeStream rId acc (Just inter)
+            consumeStream rId acc pending emitted sigs (Just inter)
           Just (SseError code msg) ->
             throwError $
               llmError (code <> ": " <> msg) Nothing Nothing
           Just _ ->
-            consumeStream rId acc mbCompleted
+            consumeStream rId acc pending emitted sigs mbCompleted
 
       toTokenUsage Nothing = Nothing
       toTokenUsage (Just Usage {..}) =
diff --git a/test/Test/Langchain/Provider/GeminiSpec.hs b/test/Test/Langchain/Provider/GeminiSpec.hs
--- a/test/Test/Langchain/Provider/GeminiSpec.hs
+++ b/test/Test/Langchain/Provider/GeminiSpec.hs
@@ -163,6 +163,58 @@
                   case (events, reverse events) of
                     (LLMStart {} : _, LLMEnd {} : _) -> pure ()
                     other -> assertFailure ("Unexpected events: " ++ show other)
+        , testCase "stream emits toolCallDelta chunks from step.start/step.delta/step.stop" $ do
+            let sseBody =
+                  "data: {\"event_type\": \"step.delta\", \"index\": 0, \"delta\": {\"type\": \"text\", \"text\": \"Checking \"}}\n\n"
+                    <> "data: {\"event_type\": \"step.start\", \"index\": 1, \"step\": {\"type\": \"function_call\", \"id\": \"call_g1\", \"name\": \"get_weather\", \"arguments\": {}}}\n\n"
+                    <> "data: {\"event_type\": \"step.delta\", \"index\": 1, \"delta\": {\"type\": \"arguments\", \"arguments\": \"{\\\"city\\\":\\\"Paris\\\"}\"}}\n\n"
+                    <> "data: {\"event_type\": \"step.stop\", \"index\": 1}\n\n"
+                    <> "data: {\"event_type\": \"interaction.completed\", \"interaction\": {\"id\": \"v1_tc\", \"status\": \"requires_action\", \"steps\": [{\"type\": \"model_output\", \"content\": [{\"type\": \"text\", \"text\": \"Checking \"}]}, {\"type\": \"function_call\", \"id\": \"call_g1\", \"name\": \"get_weather\", \"arguments\": {\"city\": \"Paris\"}}]}}\n\n"
+                app _req respond =
+                  respond $
+                    responseStream status200 [("Content-Type", "text/event-stream")] $ \write flush -> do
+                      write (Builder.lazyByteString sseBody)
+                      flush
+                expectedTc =
+                  ToolCall
+                    { toolCallId = "call_g1"
+                    , toolCallType = "function"
+                    , toolCallName = "get_weather"
+                    , toolCallArguments = [aesonQQ|{"city": "Paris"}|]
+                    }
+            withMockServer app $ \url -> do
+              let provider = newGemini "fake-key" "gemini-3.6-flash" (Just url)
+              eEvents <-
+                runResourceT $
+                  runExceptT $
+                    collectEvents $
+                      stream provider [userMessage "Weather in Paris?"] Nothing
+              case eEvents of
+                Left err -> assertFailure (show err)
+                Right events -> do
+                  let toolChunks = [tc | LLMChunk _ _ (Just tc) <- events]
+                  toolChunks @?= [expectedTc]
+                  case reverse events of
+                    LLMEnd _ finalMsg _ : _ ->
+                      messageToolCalls finalMsg @?= Just [expectedTc]
+                    _ -> assertFailure ("Expected LLMEnd, got: " ++ show events)
+        , testCase "stream emits toolCallDelta from interaction.completed fallback" $ do
+            let sseBody =
+                  "data: {\"event_type\": \"interaction.completed\", \"interaction\": {\"id\": \"v1_tc2\", \"status\": \"requires_action\", \"steps\": [{\"type\": \"function_call\", \"id\": \"call_g2\", \"name\": \"ping\", \"arguments\": {}}]}}\n\n"
+                app _req respond =
+                  respond $
+                    responseStream status200 [("Content-Type", "text/event-stream")] $ \write flush -> do
+                      write (Builder.lazyByteString sseBody)
+                      flush
+                expectedTc = ToolCall "call_g2" "function" "ping" [aesonQQ|{}|]
+            withMockServer app $ \url -> do
+              let provider = newGemini "fake-key" "gemini-3.6-flash" (Just url)
+              eEvents <- runResourceT $ runExceptT $ collectEvents $ stream provider [userMessage "Ping"] Nothing
+              case eEvents of
+                Left err -> assertFailure (show err)
+                Right events -> do
+                  let toolChunks = [tc | LLMChunk _ _ (Just tc) <- events]
+                  toolChunks @?= [expectedTc]
         ]
     , testGroup
         "Embeddings GeminiEmbeddings (Mock)"
