llama-stack-haystack 1.1.0__tar.gz → 1.2.0__tar.gz
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.
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/CHANGELOG.md +19 -1
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/PKG-INFO +8 -15
- llama_stack_haystack-1.2.0/README.md +15 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/examples/llama-stack-with-tools.py +1 -1
- llama_stack_haystack-1.2.0/pydoc/config_docusaurus.yml +28 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/pyproject.toml +1 -1
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/src/haystack_integrations/components/generators/llama_stack/chat/chat_generator.py +7 -7
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/tests/test_llama_stack_chat_generator.py +127 -18
- llama_stack_haystack-1.1.0/README.md +0 -21
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/.gitignore +0 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/LICENSE.txt +0 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/pydoc/config.yml +0 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/src/haystack_integrations/components/generators/llama_stack/__init__.py +0 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/src/haystack_integrations/components/generators/llama_stack/chat/__init__.py +0 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/src/haystack_integrations/components/generators/py.typed +0 -0
- {llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/tests/__init__.py +0 -0
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/llama_stack-v1.1.1] - 2025-08-22
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### 🧹 Chores
|
|
7
|
+
|
|
8
|
+
- Standardize readmes - part 2 (#2205)
|
|
9
|
+
|
|
10
|
+
### 🌀 Miscellaneous
|
|
11
|
+
|
|
12
|
+
- Fix: Remove openai pin in llama-stack integration (#2210)
|
|
13
|
+
|
|
14
|
+
## [integrations/llama_stack-v1.1.0] - 2025-08-08
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### 🌀 Miscellaneous
|
|
18
|
+
|
|
19
|
+
- Chore: Unpin Llama Stack version (#2171)
|
|
20
|
+
|
|
3
21
|
## [integrations/llama_stack-v1.0.1] - 2025-08-08
|
|
4
22
|
|
|
5
23
|
### 🐛 Bug Fixes
|
|
6
24
|
|
|
7
25
|
- Update the command for Llama Stack server (#2097)
|
|
8
|
-
- Pin openai to `<=1.99.
|
|
26
|
+
- Pin openai to `<=1.99.2` avoid errors in Llama Stack integration (#2169)
|
|
9
27
|
|
|
10
28
|
|
|
11
29
|
## [integrations/llama_stack-v1.0.0] - 2025-07-11
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llama-stack-haystack
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: Use Llama Stack framework for text generation
|
|
5
5
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/llama-stack#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
|
|
@@ -16,9 +16,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
16
16
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
17
17
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
18
18
|
Requires-Python: >=3.12
|
|
19
|
-
Requires-Dist: haystack-ai>=2.
|
|
19
|
+
Requires-Dist: haystack-ai>=2.19.0
|
|
20
20
|
Requires-Dist: llama-stack>=0.2.17
|
|
21
|
-
Requires-Dist: openai<=1.99.1
|
|
22
21
|
Description-Content-Type: text/markdown
|
|
23
22
|
|
|
24
23
|
# llama-stack-haystack
|
|
@@ -26,19 +25,13 @@ Description-Content-Type: text/markdown
|
|
|
26
25
|
[](https://pypi.org/project/llama-stack-haystack)
|
|
27
26
|
[](https://pypi.org/project/llama-stack-haystack)
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
- [Integration page](https://haystack.deepset.ai/integrations/llama_stack)
|
|
29
|
+
- [Changelog](https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/llama_stack/CHANGELOG.md)
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
---
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
- [License](#license)
|
|
33
|
+
## Contributing
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
Refer to the general [Contribution Guidelines](https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md).
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
pip install llama-stack-haystack
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## License
|
|
43
|
-
|
|
44
|
-
`llama-stack-haystack` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license.
|
|
37
|
+
To run integration tests locally, you need to run Ollama and the Llama Stack Server. Refer to the [workflow file](https://github.com/deepset-ai/haystack-core-integrations/blob/main/.github/workflows/llama_stack.yml) for more details.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# llama-stack-haystack
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/llama-stack-haystack)
|
|
4
|
+
[](https://pypi.org/project/llama-stack-haystack)
|
|
5
|
+
|
|
6
|
+
- [Integration page](https://haystack.deepset.ai/integrations/llama_stack)
|
|
7
|
+
- [Changelog](https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/llama_stack/CHANGELOG.md)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Contributing
|
|
12
|
+
|
|
13
|
+
Refer to the general [Contribution Guidelines](https://github.com/deepset-ai/haystack-core-integrations/blob/main/CONTRIBUTING.md).
|
|
14
|
+
|
|
15
|
+
To run integration tests locally, you need to run Ollama and the Llama Stack Server. Refer to the [workflow file](https://github.com/deepset-ai/haystack-core-integrations/blob/main/.github/workflows/llama_stack.yml) for more details.
|
{llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/examples/llama-stack-with-tools.py
RENAMED
|
@@ -34,7 +34,7 @@ weather_tool = Tool(
|
|
|
34
34
|
tool_invoker = ToolInvoker(tools=[weather_tool])
|
|
35
35
|
|
|
36
36
|
client = LlamaStackChatGenerator(
|
|
37
|
-
model="llama3.2:3b", # model
|
|
37
|
+
model="ollama/llama3.2:3b", # model depends on the inference provider used for the Llama Stack Server.
|
|
38
38
|
api_base_url="http://localhost:8321/v1/openai/v1",
|
|
39
39
|
)
|
|
40
40
|
messages = [ChatMessage.from_user("What's the weather in Tokyo?")]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
loaders:
|
|
2
|
+
- ignore_when_discovered:
|
|
3
|
+
- __init__
|
|
4
|
+
modules:
|
|
5
|
+
- haystack_integrations.components.generators.llama_stack.chat.chat_generator
|
|
6
|
+
search_path:
|
|
7
|
+
- ../src
|
|
8
|
+
type: haystack_pydoc_tools.loaders.CustomPythonLoader
|
|
9
|
+
processors:
|
|
10
|
+
- do_not_filter_modules: false
|
|
11
|
+
documented_only: true
|
|
12
|
+
expression: null
|
|
13
|
+
skip_empty_modules: true
|
|
14
|
+
type: filter
|
|
15
|
+
- type: smart
|
|
16
|
+
- type: crossref
|
|
17
|
+
renderer:
|
|
18
|
+
description: Llama Stack integration for Haystack
|
|
19
|
+
id: integrations-llama-stack
|
|
20
|
+
markdown:
|
|
21
|
+
add_member_class_prefix: false
|
|
22
|
+
add_method_class_prefix: true
|
|
23
|
+
classdef_code_block: false
|
|
24
|
+
descriptive_class_title: false
|
|
25
|
+
descriptive_module_title: true
|
|
26
|
+
filename: llama_stack.md
|
|
27
|
+
title: Llama Stack
|
|
28
|
+
type: haystack_pydoc_tools.renderers.DocusaurusRenderer
|
|
@@ -20,7 +20,7 @@ classifiers = [
|
|
|
20
20
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
21
21
|
"Programming Language :: Python :: Implementation :: PyPy",
|
|
22
22
|
]
|
|
23
|
-
dependencies = ["haystack-ai>=2.
|
|
23
|
+
dependencies = ["haystack-ai>=2.19.0", "llama-stack>=0.2.17"]
|
|
24
24
|
|
|
25
25
|
[project.urls]
|
|
26
26
|
Documentation = "https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/llama-stack#readme"
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
from typing import Any, Dict,
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
6
|
|
|
7
7
|
from haystack import component, default_from_dict, default_to_dict, logging
|
|
8
8
|
from haystack.components.generators.chat import OpenAIChatGenerator
|
|
9
9
|
from haystack.dataclasses import StreamingCallbackT
|
|
10
|
-
from haystack.tools import
|
|
10
|
+
from haystack.tools import ToolsType, deserialize_tools_or_toolset_inplace, serialize_tools_or_toolset
|
|
11
11
|
from haystack.utils import deserialize_callable, serialize_callable
|
|
12
12
|
from haystack.utils.auth import Secret
|
|
13
13
|
|
|
@@ -41,7 +41,7 @@ class LlamaStackChatGenerator(OpenAIChatGenerator):
|
|
|
41
41
|
|
|
42
42
|
messages = [ChatMessage.from_user("What's Natural Language Processing?")]
|
|
43
43
|
|
|
44
|
-
client = LlamaStackChatGenerator(model="llama3.2:3b")
|
|
44
|
+
client = LlamaStackChatGenerator(model="ollama/llama3.2:3b")
|
|
45
45
|
response = client.run(messages)
|
|
46
46
|
print(response)
|
|
47
47
|
|
|
@@ -49,7 +49,7 @@ class LlamaStackChatGenerator(OpenAIChatGenerator):
|
|
|
49
49
|
is a branch of artificial intelligence
|
|
50
50
|
>>that focuses on enabling computers to understand, interpret, and generate human language in a way that is
|
|
51
51
|
>>meaningful and useful.')], _role=<ChatRole.ASSISTANT: 'assistant'>, _name=None,
|
|
52
|
-
>>_meta={'model': 'llama3.2:3b', 'index': 0, 'finish_reason': 'stop',
|
|
52
|
+
>>_meta={'model': 'ollama/llama3.2:3b', 'index': 0, 'finish_reason': 'stop',
|
|
53
53
|
>>'usage': {'prompt_tokens': 15, 'completion_tokens': 36, 'total_tokens': 51}})]}
|
|
54
54
|
"""
|
|
55
55
|
|
|
@@ -62,7 +62,7 @@ class LlamaStackChatGenerator(OpenAIChatGenerator):
|
|
|
62
62
|
streaming_callback: Optional[StreamingCallbackT] = None,
|
|
63
63
|
generation_kwargs: Optional[Dict[str, Any]] = None,
|
|
64
64
|
timeout: Optional[int] = None,
|
|
65
|
-
tools: Optional[
|
|
65
|
+
tools: Optional[ToolsType] = None,
|
|
66
66
|
tools_strict: bool = False,
|
|
67
67
|
max_retries: Optional[int] = None,
|
|
68
68
|
http_client_kwargs: Optional[Dict[str, Any]] = None,
|
|
@@ -98,8 +98,8 @@ class LlamaStackChatGenerator(OpenAIChatGenerator):
|
|
|
98
98
|
Timeout for client calls using OpenAI API. If not set, it defaults to either the
|
|
99
99
|
`OPENAI_TIMEOUT` environment variable, or 30 seconds.
|
|
100
100
|
:param tools:
|
|
101
|
-
A list of
|
|
102
|
-
|
|
101
|
+
A list of Tool and/or Toolset objects, or a single Toolset for which the model can prepare calls.
|
|
102
|
+
Each tool should have a unique name.
|
|
103
103
|
:param tools_strict:
|
|
104
104
|
Whether to enable strict schema adherence for tool calls. If set to `True`, the model will follow exactly
|
|
105
105
|
the schema provided in the `parameters` field of the tool definition, but this may increase latency.
|
{llama_stack_haystack-1.1.0 → llama_stack_haystack-1.2.0}/tests/test_llama_stack_chat_generator.py
RENAMED
|
@@ -5,7 +5,7 @@ import pytest
|
|
|
5
5
|
import pytz
|
|
6
6
|
from haystack.components.generators.utils import print_streaming_chunk
|
|
7
7
|
from haystack.dataclasses import ChatMessage, ChatRole, StreamingChunk, ToolCall
|
|
8
|
-
from haystack.tools import Tool
|
|
8
|
+
from haystack.tools import Tool, Toolset
|
|
9
9
|
from openai.types.chat import ChatCompletion, ChatCompletionMessage
|
|
10
10
|
from openai.types.chat.chat_completion import Choice
|
|
11
11
|
|
|
@@ -25,6 +25,11 @@ def weather(city: str):
|
|
|
25
25
|
return f"The weather in {city} is sunny and 32°C"
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def population(city: str):
|
|
29
|
+
"""Get population for a given city."""
|
|
30
|
+
return f"The population of {city} is 2.2 million"
|
|
31
|
+
|
|
32
|
+
|
|
28
33
|
@pytest.fixture
|
|
29
34
|
def tools():
|
|
30
35
|
tool_parameters = {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}
|
|
@@ -38,6 +43,25 @@ def tools():
|
|
|
38
43
|
return [tool]
|
|
39
44
|
|
|
40
45
|
|
|
46
|
+
@pytest.fixture
|
|
47
|
+
def mixed_tools():
|
|
48
|
+
"""Fixture that returns a mixed list of Tool and Toolset."""
|
|
49
|
+
weather_tool = Tool(
|
|
50
|
+
name="weather",
|
|
51
|
+
description="useful to determine the weather in a given location",
|
|
52
|
+
parameters={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
|
|
53
|
+
function=weather,
|
|
54
|
+
)
|
|
55
|
+
population_tool = Tool(
|
|
56
|
+
name="population",
|
|
57
|
+
description="useful to determine the population of a given location",
|
|
58
|
+
parameters={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
|
|
59
|
+
function=population,
|
|
60
|
+
)
|
|
61
|
+
toolset = Toolset([population_tool])
|
|
62
|
+
return [weather_tool, toolset]
|
|
63
|
+
|
|
64
|
+
|
|
41
65
|
@pytest.fixture
|
|
42
66
|
def mock_chat_completion():
|
|
43
67
|
"""
|
|
@@ -46,7 +70,7 @@ def mock_chat_completion():
|
|
|
46
70
|
with patch("openai.resources.chat.completions.Completions.create") as mock_chat_completion_create:
|
|
47
71
|
completion = ChatCompletion(
|
|
48
72
|
id="foo",
|
|
49
|
-
model="llama3.2:3b",
|
|
73
|
+
model="ollama/llama3.2:3b",
|
|
50
74
|
object="chat.completion",
|
|
51
75
|
choices=[
|
|
52
76
|
Choice(
|
|
@@ -66,27 +90,27 @@ def mock_chat_completion():
|
|
|
66
90
|
|
|
67
91
|
class TestLlamaStackChatGenerator:
|
|
68
92
|
def test_init_default(self):
|
|
69
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b")
|
|
70
|
-
assert component.model == "llama3.2:3b"
|
|
93
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b")
|
|
94
|
+
assert component.model == "ollama/llama3.2:3b"
|
|
71
95
|
assert component.api_base_url == "http://localhost:8321/v1/openai/v1"
|
|
72
96
|
assert component.streaming_callback is None
|
|
73
97
|
assert not component.generation_kwargs
|
|
74
98
|
|
|
75
99
|
def test_init_with_parameters(self):
|
|
76
100
|
component = LlamaStackChatGenerator(
|
|
77
|
-
model="llama3.2:3b",
|
|
101
|
+
model="ollama/llama3.2:3b",
|
|
78
102
|
streaming_callback=print_streaming_chunk,
|
|
79
103
|
api_base_url="test-base-url",
|
|
80
104
|
generation_kwargs={"max_tokens": 10, "some_test_param": "test-params"},
|
|
81
105
|
)
|
|
82
|
-
assert component.model == "llama3.2:3b"
|
|
106
|
+
assert component.model == "ollama/llama3.2:3b"
|
|
83
107
|
assert component.streaming_callback is print_streaming_chunk
|
|
84
108
|
assert component.generation_kwargs == {"max_tokens": 10, "some_test_param": "test-params"}
|
|
85
109
|
|
|
86
110
|
def test_to_dict_default(
|
|
87
111
|
self,
|
|
88
112
|
):
|
|
89
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b")
|
|
113
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b")
|
|
90
114
|
data = component.to_dict()
|
|
91
115
|
|
|
92
116
|
assert (
|
|
@@ -95,7 +119,7 @@ class TestLlamaStackChatGenerator:
|
|
|
95
119
|
)
|
|
96
120
|
|
|
97
121
|
expected_params = {
|
|
98
|
-
"model": "llama3.2:3b",
|
|
122
|
+
"model": "ollama/llama3.2:3b",
|
|
99
123
|
"streaming_callback": None,
|
|
100
124
|
"api_base_url": "http://localhost:8321/v1/openai/v1",
|
|
101
125
|
"generation_kwargs": {},
|
|
@@ -113,7 +137,7 @@ class TestLlamaStackChatGenerator:
|
|
|
113
137
|
self,
|
|
114
138
|
):
|
|
115
139
|
component = LlamaStackChatGenerator(
|
|
116
|
-
model="llama3.2:3b",
|
|
140
|
+
model="ollama/llama3.2:3b",
|
|
117
141
|
streaming_callback=print_streaming_chunk,
|
|
118
142
|
api_base_url="test-base-url",
|
|
119
143
|
generation_kwargs={"max_tokens": 10, "some_test_param": "test-params"},
|
|
@@ -131,7 +155,7 @@ class TestLlamaStackChatGenerator:
|
|
|
131
155
|
)
|
|
132
156
|
|
|
133
157
|
expected_params = {
|
|
134
|
-
"model": "llama3.2:3b",
|
|
158
|
+
"model": "ollama/llama3.2:3b",
|
|
135
159
|
"api_base_url": "test-base-url",
|
|
136
160
|
"streaming_callback": "haystack.components.generators.utils.print_streaming_chunk",
|
|
137
161
|
"generation_kwargs": {"max_tokens": 10, "some_test_param": "test-params"},
|
|
@@ -153,7 +177,7 @@ class TestLlamaStackChatGenerator:
|
|
|
153
177
|
"haystack_integrations.components.generators.llama_stack.chat.chat_generator.LlamaStackChatGenerator"
|
|
154
178
|
),
|
|
155
179
|
"init_parameters": {
|
|
156
|
-
"model": "llama3.2:3b",
|
|
180
|
+
"model": "ollama/llama3.2:3b",
|
|
157
181
|
"api_base_url": "test-base-url",
|
|
158
182
|
"streaming_callback": "haystack.components.generators.utils.print_streaming_chunk",
|
|
159
183
|
"generation_kwargs": {"max_tokens": 10, "some_test_param": "test-params"},
|
|
@@ -165,7 +189,7 @@ class TestLlamaStackChatGenerator:
|
|
|
165
189
|
},
|
|
166
190
|
}
|
|
167
191
|
component = LlamaStackChatGenerator.from_dict(data)
|
|
168
|
-
assert component.model == "llama3.2:3b"
|
|
192
|
+
assert component.model == "ollama/llama3.2:3b"
|
|
169
193
|
assert component.streaming_callback is print_streaming_chunk
|
|
170
194
|
assert component.api_base_url == "test-base-url"
|
|
171
195
|
assert component.generation_kwargs == {"max_tokens": 10, "some_test_param": "test-params"}
|
|
@@ -175,8 +199,33 @@ class TestLlamaStackChatGenerator:
|
|
|
175
199
|
assert component.max_retries == 10
|
|
176
200
|
assert not component.tools_strict
|
|
177
201
|
|
|
202
|
+
def test_init_with_mixed_tools(self):
|
|
203
|
+
def tool_fn(city: str) -> str:
|
|
204
|
+
return city
|
|
205
|
+
|
|
206
|
+
weather_tool = Tool(
|
|
207
|
+
name="weather",
|
|
208
|
+
description="Weather lookup",
|
|
209
|
+
parameters={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
|
|
210
|
+
function=tool_fn,
|
|
211
|
+
)
|
|
212
|
+
population_tool = Tool(
|
|
213
|
+
name="population",
|
|
214
|
+
description="Population lookup",
|
|
215
|
+
parameters={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
|
|
216
|
+
function=tool_fn,
|
|
217
|
+
)
|
|
218
|
+
toolset = Toolset([population_tool])
|
|
219
|
+
|
|
220
|
+
generator = LlamaStackChatGenerator(
|
|
221
|
+
model="ollama/llama3.2:3b",
|
|
222
|
+
tools=[weather_tool, toolset],
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
assert generator.tools == [weather_tool, toolset]
|
|
226
|
+
|
|
178
227
|
def test_run(self, chat_messages, mock_chat_completion): # noqa: ARG002
|
|
179
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b")
|
|
228
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b")
|
|
180
229
|
response = component.run(chat_messages)
|
|
181
230
|
|
|
182
231
|
# check that the component returns the correct ChatMessage response
|
|
@@ -188,7 +237,7 @@ class TestLlamaStackChatGenerator:
|
|
|
188
237
|
|
|
189
238
|
def test_run_with_params(self, chat_messages, mock_chat_completion):
|
|
190
239
|
component = LlamaStackChatGenerator(
|
|
191
|
-
model="llama3.2:3b",
|
|
240
|
+
model="ollama/llama3.2:3b",
|
|
192
241
|
generation_kwargs={"max_tokens": 10, "temperature": 0.5},
|
|
193
242
|
)
|
|
194
243
|
response = component.run(chat_messages)
|
|
@@ -208,7 +257,7 @@ class TestLlamaStackChatGenerator:
|
|
|
208
257
|
@pytest.mark.integration
|
|
209
258
|
def test_live_run(self):
|
|
210
259
|
chat_messages = [ChatMessage.from_user("What's the capital of France")]
|
|
211
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b")
|
|
260
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b")
|
|
212
261
|
results = component.run(chat_messages)
|
|
213
262
|
assert len(results["replies"]) == 1
|
|
214
263
|
message: ChatMessage = results["replies"][0]
|
|
@@ -228,7 +277,7 @@ class TestLlamaStackChatGenerator:
|
|
|
228
277
|
self.responses += chunk.content if chunk.content else ""
|
|
229
278
|
|
|
230
279
|
callback = Callback()
|
|
231
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b", streaming_callback=callback)
|
|
280
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b", streaming_callback=callback)
|
|
232
281
|
results = component.run([ChatMessage.from_user("What's the capital of France?")])
|
|
233
282
|
|
|
234
283
|
assert len(results["replies"]) == 1
|
|
@@ -244,7 +293,7 @@ class TestLlamaStackChatGenerator:
|
|
|
244
293
|
@pytest.mark.integration
|
|
245
294
|
def test_live_run_with_tools(self, tools):
|
|
246
295
|
chat_messages = [ChatMessage.from_user("What's the weather like in Paris?")]
|
|
247
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b", tools=tools)
|
|
296
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b", tools=tools)
|
|
248
297
|
results = component.run(chat_messages)
|
|
249
298
|
assert len(results["replies"]) == 1
|
|
250
299
|
message = results["replies"][0]
|
|
@@ -263,7 +312,7 @@ class TestLlamaStackChatGenerator:
|
|
|
263
312
|
Integration test that the LlamaStackChatGenerator component can run with tools and get a response.
|
|
264
313
|
"""
|
|
265
314
|
initial_messages = [ChatMessage.from_user("What's the weather like in Paris?")]
|
|
266
|
-
component = LlamaStackChatGenerator(model="llama3.2:3b", tools=tools)
|
|
315
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b", tools=tools)
|
|
267
316
|
results = component.run(messages=initial_messages, generation_kwargs={"tool_choice": "auto"})
|
|
268
317
|
|
|
269
318
|
assert len(results["replies"]) > 0, "No replies received"
|
|
@@ -298,3 +347,63 @@ class TestLlamaStackChatGenerator:
|
|
|
298
347
|
assert not final_message.tool_call
|
|
299
348
|
assert len(final_message.text) > 0
|
|
300
349
|
assert "paris" in final_message.text.lower()
|
|
350
|
+
|
|
351
|
+
@pytest.mark.integration
|
|
352
|
+
def test_live_run_with_mixed_tools(self, mixed_tools):
|
|
353
|
+
"""
|
|
354
|
+
Integration test that verifies LlamaStackChatGenerator works with mixed Tool and Toolset.
|
|
355
|
+
This tests that the LLM can correctly invoke tools from both a standalone Tool and a Toolset.
|
|
356
|
+
"""
|
|
357
|
+
initial_messages = [
|
|
358
|
+
ChatMessage.from_user("What's the weather like in Paris and what is the population of Berlin?")
|
|
359
|
+
]
|
|
360
|
+
component = LlamaStackChatGenerator(model="ollama/llama3.2:3b", tools=mixed_tools)
|
|
361
|
+
results = component.run(messages=initial_messages)
|
|
362
|
+
|
|
363
|
+
assert len(results["replies"]) > 0, "No replies received"
|
|
364
|
+
|
|
365
|
+
# Find the message with tool calls
|
|
366
|
+
tool_call_message = None
|
|
367
|
+
for message in results["replies"]:
|
|
368
|
+
if message.tool_calls:
|
|
369
|
+
tool_call_message = message
|
|
370
|
+
break
|
|
371
|
+
|
|
372
|
+
assert tool_call_message is not None, "No message with tool call found"
|
|
373
|
+
assert isinstance(tool_call_message, ChatMessage), "Tool message is not a ChatMessage instance"
|
|
374
|
+
assert ChatMessage.is_from(tool_call_message, ChatRole.ASSISTANT), "Tool message is not from the assistant"
|
|
375
|
+
|
|
376
|
+
tool_calls = tool_call_message.tool_calls
|
|
377
|
+
assert len(tool_calls) == 2, f"Expected 2 tool calls, got {len(tool_calls)}"
|
|
378
|
+
|
|
379
|
+
# Verify we got calls to both weather and population tools
|
|
380
|
+
tool_names = {tc.tool_name for tc in tool_calls}
|
|
381
|
+
assert "weather" in tool_names, "Expected 'weather' tool call"
|
|
382
|
+
assert "population" in tool_names, "Expected 'population' tool call"
|
|
383
|
+
|
|
384
|
+
# Verify tool call details
|
|
385
|
+
for tool_call in tool_calls:
|
|
386
|
+
assert tool_call.id, "Tool call does not contain value for 'id' key"
|
|
387
|
+
assert tool_call.tool_name in ["weather", "population"]
|
|
388
|
+
assert "city" in tool_call.arguments
|
|
389
|
+
assert tool_call.arguments["city"] in ["Paris", "Berlin"]
|
|
390
|
+
assert tool_call_message.meta["finish_reason"] == "tool_calls"
|
|
391
|
+
|
|
392
|
+
# Mock the response we'd get from ToolInvoker
|
|
393
|
+
tool_result_messages = []
|
|
394
|
+
for tool_call in tool_calls:
|
|
395
|
+
if tool_call.tool_name == "weather":
|
|
396
|
+
result = "The weather in Paris is sunny and 32°C"
|
|
397
|
+
else: # population
|
|
398
|
+
result = "The population of Berlin is 2.2 million"
|
|
399
|
+
tool_result_messages.append(ChatMessage.from_tool(tool_result=result, origin=tool_call))
|
|
400
|
+
|
|
401
|
+
new_messages = [*initial_messages, tool_call_message, *tool_result_messages]
|
|
402
|
+
results = component.run(new_messages)
|
|
403
|
+
|
|
404
|
+
assert len(results["replies"]) == 1
|
|
405
|
+
final_message = results["replies"][0]
|
|
406
|
+
assert not final_message.tool_call
|
|
407
|
+
assert len(final_message.text) > 0
|
|
408
|
+
assert "paris" in final_message.text.lower()
|
|
409
|
+
assert "berlin" in final_message.text.lower()
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# llama-stack-haystack
|
|
2
|
-
|
|
3
|
-
[](https://pypi.org/project/llama-stack-haystack)
|
|
4
|
-
[](https://pypi.org/project/llama-stack-haystack)
|
|
5
|
-
|
|
6
|
-
-----
|
|
7
|
-
|
|
8
|
-
**Table of Contents**
|
|
9
|
-
|
|
10
|
-
- [Installation](#installation)
|
|
11
|
-
- [License](#license)
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
```console
|
|
16
|
-
pip install llama-stack-haystack
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## License
|
|
20
|
-
|
|
21
|
-
`llama-stack-haystack` is distributed under the terms of the [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html) license.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|