Skip to content

Conversation

devdattatalele
Copy link

@devdattatalele devdattatalele commented Aug 17, 2025

Summary

Fixes issue #299 where the Ollama client fails with 'generator' object has no attribute 'raw_response' error when using stream=True.

Correct Implementation

  • OllamaClient consistently returns GeneratorOutput for both streaming and non-streaming
  • raw_response contains the streaming generator (following established contract)
  • data remains None until final output is processed by Generator component
  • Maintains interface consistency across all model clients
  • Preserves polymorphism - all clients return the same type

Previous Approach (Fixed)

The initial implementation incorrectly returned raw generators directly, breaking:

  • Interface consistency across model clients
  • Generator component expectations
  • SOLID principles (Single Responsibility, Open/Closed)

Technical Changes

1. OllamaClient (adalflow/components/model_client/ollama_client.py)

# CORRECT: Consistent GeneratorOutput return
if isinstance(completion, GeneratorType):
    return GeneratorOutput(
        data=None,                    # Final output processed later
        raw_response=completion,      # Streaming iterator
        api_response=completion       # Original response
    )

2. Generator Core (adalflow/core/generator.py)

  • Removed incorrect type checking logic that was specific to OllamaClient
  • Restored original error handling that works for all model clients
  • Maintains single responsibility principle

3. Test Updates (tests/test_ollama_client.py)

Updated to follow proper streaming contract:

  • parsed.raw_response → streaming iterator
  • parsed.dataNone (until consumed)
  • Maintains GeneratorOutput consistency

Test Results

# All tests passing
pytest tests/test_ollama_client.py -v
======================== 10 passed ========================

#299

Resolves issue SylphAI-Inc#299 where OllamaClient failed with 'generator' object has no attribute 'raw_response' error when using stream=True.

Changes:
- Modified OllamaClient.parse_chat_completion to return raw generators directly for streaming
- Updated Generator error handling to prevent generator objects in raw_response field
- Added proper type checking for both sync and async generators
- Updated tests to reflect correct streaming behavior

The fix ensures that streaming generators are handled correctly by the Generator component rather than being incorrectly wrapped in GeneratorOutput.raw_response.
output = self._post_call(completion)
except Exception as e:
log.error(f"Error processing the output: {e}")
# Check if completion is a generator to avoid placing generator object in raw_response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we almost never change the generator output. Raw_response is for streaming, data is for final parsed result

Copy link
Member

@liyin2015 liyin2015 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check anthropic client on how to handle the streaming. Eventually the standard is to convert to openai's responses api standard.

Copy link
Member

@liyin2015 liyin2015 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try this code,

from adalflow.components.model_client.ollama_client import OllamaClient
from adalflow.core import Generator

stream_generator = Generator(
    model_client=OllamaClient(host="http://localhost:11434"),
    model_kwargs={
        "model": "gpt-oss:20b",
        "stream": True,  # Enable streaming
    }
)

async def test_ollama_streaming():
    # async call with streaming
    output = await stream_generator.acall(prompt_kwargs={"input_str": "Why is the sky blue?"})

    async for chunk in output.raw_response:
        print(chunk["message"]["content"], end='', flush=True)


if __name__ == "__main__":
    import asyncio
    asyncio.run(test_ollama_streaming())

It works for streaming.

Previous implementation broke interface consistency and created architectural problems.

Corrected approach:
- OllamaClient consistently returns GeneratorOutput for all cases
- raw_response contains the streaming generator (following Anthropic client pattern)
- data remains None until final output is processed
- Removed incorrect type checking from Generator core component
- Maintains polymorphism across all model clients

This follows the established contract:
- raw_response = streaming chunks/iterator
- data = finalized complete output (processed later)

Fixes maintain full compatibility with Generator component and preserve
all existing functionality (processors, tracking, caching).

All tests pass and integration with Generator component verified.
@devdattatalele
Copy link
Author

@liyin2015 I've updated the implementation based on your feedback. You mentioned that raw_response should stay for streaming and to check the Anthropic client for reference. I tested it with your code example it works perfectly!

Copy link
Member

@liyin2015 liyin2015 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check the comments

except Exception as e:
log.error(f"Error processing the output processors: {e}")
output.error = str(e)
# Check if this is a streaming response (generator/iterator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this pr does not do much. and we cant force the data to None either. It is supposed to be the final complete output data, which should be handled in ollama_client, where u have to collect all stream and save the complete one in this field. you can see example in https://github.com/SylphAI-Inc/AdalFlow/blob/main/adalflow/adalflow/components/model_client/anthropic_client.py

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep the generator not changed at all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants