portazgo 0.1.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.
- portazgo-0.1.0/LICENSE +17 -0
- portazgo-0.1.0/MANIFEST.in +4 -0
- portazgo-0.1.0/PKG-INFO +247 -0
- portazgo-0.1.0/README.md +218 -0
- portazgo-0.1.0/pyproject.toml +75 -0
- portazgo-0.1.0/setup.cfg +4 -0
- portazgo-0.1.0/src/cohorte/__init__.py +36 -0
- portazgo-0.1.0/src/cohorte/agent.py +202 -0
- portazgo-0.1.0/src/cohorte/chats.py +45 -0
- portazgo-0.1.0/src/cohorte/default_impl.py +427 -0
- portazgo-0.1.0/src/cohorte/lang_graph.py +97 -0
- portazgo-0.1.0/src/cohorte/utils.py +149 -0
- portazgo-0.1.0/src/portazgo.egg-info/PKG-INFO +247 -0
- portazgo-0.1.0/src/portazgo.egg-info/SOURCES.txt +18 -0
- portazgo-0.1.0/src/portazgo.egg-info/dependency_links.txt +1 -0
- portazgo-0.1.0/src/portazgo.egg-info/requires.txt +12 -0
- portazgo-0.1.0/src/portazgo.egg-info/top_level.txt +1 -0
- portazgo-0.1.0/tests/test_agent.py +189 -0
- portazgo-0.1.0/tests/test_chats.py +29 -0
- portazgo-0.1.0/tests/test_utils.py +90 -0
portazgo-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Copyright 2025 IBM, Red Hat
|
|
6
|
+
|
|
7
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
you may not use this file except in compliance with the License.
|
|
9
|
+
You may obtain a copy of the License at
|
|
10
|
+
|
|
11
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
|
|
13
|
+
Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
See the License for the specific language governing permissions and
|
|
17
|
+
limitations under the License.
|
portazgo-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: portazgo
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pluggable agent SDK to talk to Llama Stack using a cohort of agents (default Llama Stack Responses API or LangGraph)
|
|
5
|
+
Author: Alpha Hack Program
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Repository, https://github.com/alpha-hack-program/llama-stack-demo
|
|
8
|
+
Project-URL: Documentation, https://github.com/alpha-hack-program/llama-stack-demo#readme
|
|
9
|
+
Keywords: rag,ragas,llama-stack,langgraph,agent
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: httpx
|
|
19
|
+
Requires-Dist: llama-stack-client<0.4,>=0.3.5
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
23
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
24
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0; extra == "dev"
|
|
26
|
+
Provides-Extra: langgraph
|
|
27
|
+
Requires-Dist: langgraph>=0.2; extra == "langgraph"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# cohorte
|
|
31
|
+
|
|
32
|
+
Pluggable agent backends for RAGAS dataset generation. Use the **default** backend (Llama Stack Responses API) or a **lang-graph** backend (stub for future implementation).
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
From source with **uv** (recommended):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
cd cohorte
|
|
40
|
+
uv sync --extra dev
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
With optional LangGraph extra (when that backend is implemented):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
uv sync --extra dev --extra langgraph
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
With pip (from source):
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install -e .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For PyPI (once published):
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install cohorte
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
### Agent with type
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from cohorte import Agent
|
|
67
|
+
|
|
68
|
+
# Default: Llama Stack Responses API (same as ragas_pipeline / ragas_dataset_generator)
|
|
69
|
+
agent = Agent(type="default")
|
|
70
|
+
ragas_dataset = agent.generate_ragas_dataset(
|
|
71
|
+
base_dataset=base_dataset,
|
|
72
|
+
client=llama_stack_client,
|
|
73
|
+
model_id="my-model",
|
|
74
|
+
vector_store_id=vs_id,
|
|
75
|
+
mcp_tools=mcp_tools,
|
|
76
|
+
instructions="Optional system prompt",
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Single query: invoke (normal agent call)
|
|
81
|
+
|
|
82
|
+
Same parameter shape as `generate_ragas_dataset`, but for one input. The name follows **LangChain/LangGraph** (`agent.invoke(input)`):
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from cohorte import Agent
|
|
86
|
+
|
|
87
|
+
agent = Agent(type="default")
|
|
88
|
+
result = agent.invoke(
|
|
89
|
+
"What is the capital of France?",
|
|
90
|
+
client=llama_stack_client,
|
|
91
|
+
model_id="my-model",
|
|
92
|
+
vector_store_id=vs_id,
|
|
93
|
+
mcp_tools=[], # or list of MCP tool configs
|
|
94
|
+
instructions="You are a helpful assistant.",
|
|
95
|
+
)
|
|
96
|
+
# result["answer"] -> str
|
|
97
|
+
# result["contexts"] -> list[str] (retrieved chunks + non–file_search tool responses)
|
|
98
|
+
# result["tool_calls"] -> list[dict]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Chat with history (e.g. chatbots)
|
|
102
|
+
|
|
103
|
+
Pass `messages` so the model sees previous turns. Each message is `{"role": "user"|"assistant"|"system", "content": str}`:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
history = [
|
|
107
|
+
{"role": "user", "content": "My name is Alice."},
|
|
108
|
+
{"role": "assistant", "content": "Nice to meet you, Alice!"},
|
|
109
|
+
]
|
|
110
|
+
result = agent.invoke(
|
|
111
|
+
"What's my name?",
|
|
112
|
+
client=client,
|
|
113
|
+
model_id=model_id,
|
|
114
|
+
vector_store_id=vs_id,
|
|
115
|
+
mcp_tools=[],
|
|
116
|
+
messages=history,
|
|
117
|
+
)
|
|
118
|
+
# result["answer"] can refer to the conversation (e.g. "Your name is Alice.")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Streaming: invoke_stream
|
|
122
|
+
|
|
123
|
+
For real-time display (e.g. Streamlit), use `invoke_stream`. It yields events: `content_delta` (chunk of text) then `done` (final answer + contexts + tool_calls). If the backend does not support token-level streaming, the full answer is sent as one delta then `done`.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
for event in agent.invoke_stream(
|
|
127
|
+
"Explain RAG in one sentence.",
|
|
128
|
+
client=client,
|
|
129
|
+
model_id=model_id,
|
|
130
|
+
vector_store_id=vs_id,
|
|
131
|
+
mcp_tools=[],
|
|
132
|
+
messages=st.session_state.messages, # optional history
|
|
133
|
+
):
|
|
134
|
+
if event["type"] == "content_delta":
|
|
135
|
+
print(event["delta"], end="", flush=True)
|
|
136
|
+
elif event["type"] == "done":
|
|
137
|
+
answer, contexts, tool_calls = event["answer"], event["contexts"], event["tool_calls"]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Streamlit chat example (with history + streaming)
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
import streamlit as st
|
|
144
|
+
from cohorte import Agent
|
|
145
|
+
|
|
146
|
+
# Init session state
|
|
147
|
+
if "messages" not in st.session_state:
|
|
148
|
+
st.session_state.messages = []
|
|
149
|
+
|
|
150
|
+
agent = Agent(type="default")
|
|
151
|
+
# client, model_id, vector_store_id from your config (e.g. sidebar)
|
|
152
|
+
|
|
153
|
+
# Display history
|
|
154
|
+
for msg in st.session_state.messages:
|
|
155
|
+
with st.chat_message(msg["role"]):
|
|
156
|
+
st.markdown(msg["content"])
|
|
157
|
+
|
|
158
|
+
if prompt := st.chat_input("Your message"):
|
|
159
|
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
|
160
|
+
with st.chat_message("user"):
|
|
161
|
+
st.markdown(prompt)
|
|
162
|
+
|
|
163
|
+
with st.chat_message("assistant"):
|
|
164
|
+
placeholder = st.empty()
|
|
165
|
+
full = ""
|
|
166
|
+
for event in agent.invoke_stream(
|
|
167
|
+
prompt,
|
|
168
|
+
client=client,
|
|
169
|
+
model_id=model_id,
|
|
170
|
+
vector_store_id=vector_store_id,
|
|
171
|
+
mcp_tools=[],
|
|
172
|
+
messages=st.session_state.messages[:-1], # history (exclude current)
|
|
173
|
+
):
|
|
174
|
+
if event["type"] == "content_delta":
|
|
175
|
+
full += event["delta"]
|
|
176
|
+
placeholder.markdown(full + "▌")
|
|
177
|
+
placeholder.markdown(full)
|
|
178
|
+
st.session_state.messages.append({"role": "assistant", "content": full})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# LangGraph backend (not yet implemented; will raise NotImplementedError)
|
|
183
|
+
agent = Agent(type="lang-graph")
|
|
184
|
+
# agent.invoke(...) # NotImplementedError
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Utilities
|
|
188
|
+
|
|
189
|
+
The library also exposes helpers used by the default backend, useful for custom pipelines:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from cohorte import strip_think_blocks, serialize_for_json, extract_tool_calls
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- `strip_think_blocks(text)` – remove `<think>...</think>` blocks from model output.
|
|
196
|
+
- `serialize_for_json(val)` – convert objects to JSON-serializable form.
|
|
197
|
+
- `extract_tool_calls(response)` – extract tool calls from a Llama Stack response.
|
|
198
|
+
|
|
199
|
+
## Testing a simple invoke
|
|
200
|
+
|
|
201
|
+
**Option 1: Unit tests (no Llama Stack server)**
|
|
202
|
+
Runs `invoke` against a mock client so you can confirm the API shape:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
cd cohorte
|
|
206
|
+
uv run pytest tests/test_agent.py -v -k invoke
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Option 2: Real invoke against Llama Stack**
|
|
210
|
+
Use the example script (requires a running Llama Stack and a vector store):
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
cd cohorte
|
|
214
|
+
export LLAMA_STACK_HOST=localhost
|
|
215
|
+
export LLAMA_STACK_PORT=8080
|
|
216
|
+
# optional: AGENT_VECTOR_STORE_NAME=rag-store, AGENT_MODEL_ID="your/model"
|
|
217
|
+
|
|
218
|
+
uv run python examples/simple_invoke.py "What is 2+2?"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
You can pass any question as arguments; default is `"What is 2+2?"`.
|
|
222
|
+
|
|
223
|
+
**Option 3: OpenShift (oc)**
|
|
224
|
+
If Llama Stack is exposed on OpenShift, use the helper script to get `APPS_DOMAIN` and run the example:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
cd cohorte
|
|
228
|
+
./scripts/run_invoke_oc.sh "What is 2+2?"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
The script sources `.env` (for `PROJECT`, etc.), runs `oc get ingresses.config.openshift.io cluster` for the apps domain, sets `LLAMA_STACK_HOST` to `llama-stack-demo-route-${PROJECT}.${APPS_DOMAIN}`, then runs the example with any arguments you pass.
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
Uses [uv](https://docs.astral.sh/uv/) for the venv and running tools. From the cohorte directory:
|
|
236
|
+
|
|
237
|
+
- **Create venv and install deps:** `make install-dev` (or `uv sync --extra dev`)
|
|
238
|
+
- **Lock dependencies:** `make lock` (or `uv lock`)
|
|
239
|
+
- **Lint:** `make lint` (ruff via `uv run`)
|
|
240
|
+
- **Format:** `make format`
|
|
241
|
+
- **Tests:** `make test` (or `uv run pytest tests`)
|
|
242
|
+
- **Coverage:** `make coverage`
|
|
243
|
+
- **Build:** `make build` (or `uv run python -m build`)
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
portazgo-0.1.0/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# cohorte
|
|
2
|
+
|
|
3
|
+
Pluggable agent backends for RAGAS dataset generation. Use the **default** backend (Llama Stack Responses API) or a **lang-graph** backend (stub for future implementation).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
From source with **uv** (recommended):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd cohorte
|
|
11
|
+
uv sync --extra dev
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
With optional LangGraph extra (when that backend is implemented):
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv sync --extra dev --extra langgraph
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
With pip (from source):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install -e .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For PyPI (once published):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install cohorte
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
### Agent with type
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from cohorte import Agent
|
|
38
|
+
|
|
39
|
+
# Default: Llama Stack Responses API (same as ragas_pipeline / ragas_dataset_generator)
|
|
40
|
+
agent = Agent(type="default")
|
|
41
|
+
ragas_dataset = agent.generate_ragas_dataset(
|
|
42
|
+
base_dataset=base_dataset,
|
|
43
|
+
client=llama_stack_client,
|
|
44
|
+
model_id="my-model",
|
|
45
|
+
vector_store_id=vs_id,
|
|
46
|
+
mcp_tools=mcp_tools,
|
|
47
|
+
instructions="Optional system prompt",
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Single query: invoke (normal agent call)
|
|
52
|
+
|
|
53
|
+
Same parameter shape as `generate_ragas_dataset`, but for one input. The name follows **LangChain/LangGraph** (`agent.invoke(input)`):
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from cohorte import Agent
|
|
57
|
+
|
|
58
|
+
agent = Agent(type="default")
|
|
59
|
+
result = agent.invoke(
|
|
60
|
+
"What is the capital of France?",
|
|
61
|
+
client=llama_stack_client,
|
|
62
|
+
model_id="my-model",
|
|
63
|
+
vector_store_id=vs_id,
|
|
64
|
+
mcp_tools=[], # or list of MCP tool configs
|
|
65
|
+
instructions="You are a helpful assistant.",
|
|
66
|
+
)
|
|
67
|
+
# result["answer"] -> str
|
|
68
|
+
# result["contexts"] -> list[str] (retrieved chunks + non–file_search tool responses)
|
|
69
|
+
# result["tool_calls"] -> list[dict]
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Chat with history (e.g. chatbots)
|
|
73
|
+
|
|
74
|
+
Pass `messages` so the model sees previous turns. Each message is `{"role": "user"|"assistant"|"system", "content": str}`:
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
history = [
|
|
78
|
+
{"role": "user", "content": "My name is Alice."},
|
|
79
|
+
{"role": "assistant", "content": "Nice to meet you, Alice!"},
|
|
80
|
+
]
|
|
81
|
+
result = agent.invoke(
|
|
82
|
+
"What's my name?",
|
|
83
|
+
client=client,
|
|
84
|
+
model_id=model_id,
|
|
85
|
+
vector_store_id=vs_id,
|
|
86
|
+
mcp_tools=[],
|
|
87
|
+
messages=history,
|
|
88
|
+
)
|
|
89
|
+
# result["answer"] can refer to the conversation (e.g. "Your name is Alice.")
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Streaming: invoke_stream
|
|
93
|
+
|
|
94
|
+
For real-time display (e.g. Streamlit), use `invoke_stream`. It yields events: `content_delta` (chunk of text) then `done` (final answer + contexts + tool_calls). If the backend does not support token-level streaming, the full answer is sent as one delta then `done`.
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
for event in agent.invoke_stream(
|
|
98
|
+
"Explain RAG in one sentence.",
|
|
99
|
+
client=client,
|
|
100
|
+
model_id=model_id,
|
|
101
|
+
vector_store_id=vs_id,
|
|
102
|
+
mcp_tools=[],
|
|
103
|
+
messages=st.session_state.messages, # optional history
|
|
104
|
+
):
|
|
105
|
+
if event["type"] == "content_delta":
|
|
106
|
+
print(event["delta"], end="", flush=True)
|
|
107
|
+
elif event["type"] == "done":
|
|
108
|
+
answer, contexts, tool_calls = event["answer"], event["contexts"], event["tool_calls"]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Streamlit chat example (with history + streaming)
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
import streamlit as st
|
|
115
|
+
from cohorte import Agent
|
|
116
|
+
|
|
117
|
+
# Init session state
|
|
118
|
+
if "messages" not in st.session_state:
|
|
119
|
+
st.session_state.messages = []
|
|
120
|
+
|
|
121
|
+
agent = Agent(type="default")
|
|
122
|
+
# client, model_id, vector_store_id from your config (e.g. sidebar)
|
|
123
|
+
|
|
124
|
+
# Display history
|
|
125
|
+
for msg in st.session_state.messages:
|
|
126
|
+
with st.chat_message(msg["role"]):
|
|
127
|
+
st.markdown(msg["content"])
|
|
128
|
+
|
|
129
|
+
if prompt := st.chat_input("Your message"):
|
|
130
|
+
st.session_state.messages.append({"role": "user", "content": prompt})
|
|
131
|
+
with st.chat_message("user"):
|
|
132
|
+
st.markdown(prompt)
|
|
133
|
+
|
|
134
|
+
with st.chat_message("assistant"):
|
|
135
|
+
placeholder = st.empty()
|
|
136
|
+
full = ""
|
|
137
|
+
for event in agent.invoke_stream(
|
|
138
|
+
prompt,
|
|
139
|
+
client=client,
|
|
140
|
+
model_id=model_id,
|
|
141
|
+
vector_store_id=vector_store_id,
|
|
142
|
+
mcp_tools=[],
|
|
143
|
+
messages=st.session_state.messages[:-1], # history (exclude current)
|
|
144
|
+
):
|
|
145
|
+
if event["type"] == "content_delta":
|
|
146
|
+
full += event["delta"]
|
|
147
|
+
placeholder.markdown(full + "▌")
|
|
148
|
+
placeholder.markdown(full)
|
|
149
|
+
st.session_state.messages.append({"role": "assistant", "content": full})
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# LangGraph backend (not yet implemented; will raise NotImplementedError)
|
|
154
|
+
agent = Agent(type="lang-graph")
|
|
155
|
+
# agent.invoke(...) # NotImplementedError
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Utilities
|
|
159
|
+
|
|
160
|
+
The library also exposes helpers used by the default backend, useful for custom pipelines:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
from cohorte import strip_think_blocks, serialize_for_json, extract_tool_calls
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
- `strip_think_blocks(text)` – remove `<think>...</think>` blocks from model output.
|
|
167
|
+
- `serialize_for_json(val)` – convert objects to JSON-serializable form.
|
|
168
|
+
- `extract_tool_calls(response)` – extract tool calls from a Llama Stack response.
|
|
169
|
+
|
|
170
|
+
## Testing a simple invoke
|
|
171
|
+
|
|
172
|
+
**Option 1: Unit tests (no Llama Stack server)**
|
|
173
|
+
Runs `invoke` against a mock client so you can confirm the API shape:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
cd cohorte
|
|
177
|
+
uv run pytest tests/test_agent.py -v -k invoke
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Option 2: Real invoke against Llama Stack**
|
|
181
|
+
Use the example script (requires a running Llama Stack and a vector store):
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
cd cohorte
|
|
185
|
+
export LLAMA_STACK_HOST=localhost
|
|
186
|
+
export LLAMA_STACK_PORT=8080
|
|
187
|
+
# optional: AGENT_VECTOR_STORE_NAME=rag-store, AGENT_MODEL_ID="your/model"
|
|
188
|
+
|
|
189
|
+
uv run python examples/simple_invoke.py "What is 2+2?"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
You can pass any question as arguments; default is `"What is 2+2?"`.
|
|
193
|
+
|
|
194
|
+
**Option 3: OpenShift (oc)**
|
|
195
|
+
If Llama Stack is exposed on OpenShift, use the helper script to get `APPS_DOMAIN` and run the example:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
cd cohorte
|
|
199
|
+
./scripts/run_invoke_oc.sh "What is 2+2?"
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The script sources `.env` (for `PROJECT`, etc.), runs `oc get ingresses.config.openshift.io cluster` for the apps domain, sets `LLAMA_STACK_HOST` to `llama-stack-demo-route-${PROJECT}.${APPS_DOMAIN}`, then runs the example with any arguments you pass.
|
|
203
|
+
|
|
204
|
+
## Development
|
|
205
|
+
|
|
206
|
+
Uses [uv](https://docs.astral.sh/uv/) for the venv and running tools. From the cohorte directory:
|
|
207
|
+
|
|
208
|
+
- **Create venv and install deps:** `make install-dev` (or `uv sync --extra dev`)
|
|
209
|
+
- **Lock dependencies:** `make lock` (or `uv lock`)
|
|
210
|
+
- **Lint:** `make lint` (ruff via `uv run`)
|
|
211
|
+
- **Format:** `make format`
|
|
212
|
+
- **Tests:** `make test` (or `uv run pytest tests`)
|
|
213
|
+
- **Coverage:** `make coverage`
|
|
214
|
+
- **Build:** `make build` (or `uv run python -m build`)
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
Apache-2.0. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "portazgo"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Pluggable agent SDK to talk to Llama Stack using a cohort of agents (default Llama Stack Responses API or LangGraph)"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "Apache-2.0" }
|
|
11
|
+
requires-python = ">=3.12"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Alpha Hack Program" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["rag", "ragas", "llama-stack", "langgraph", "agent"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: Apache Software License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"httpx",
|
|
25
|
+
# Pin to 0.3.x for compatibility with Llama Stack server 0.3.5.x (426 if client is 0.5.x).
|
|
26
|
+
"llama-stack-client>=0.3.5,<0.4",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=7.0",
|
|
32
|
+
"pytest-cov>=4.0",
|
|
33
|
+
"ruff>=0.1.0",
|
|
34
|
+
"build>=1.0",
|
|
35
|
+
"python-dotenv>=1.0",
|
|
36
|
+
]
|
|
37
|
+
langgraph = [
|
|
38
|
+
"langgraph>=0.2",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.urls]
|
|
42
|
+
Repository = "https://github.com/alpha-hack-program/llama-stack-demo"
|
|
43
|
+
Documentation = "https://github.com/alpha-hack-program/llama-stack-demo#readme"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools.packages.find]
|
|
46
|
+
where = ["src"]
|
|
47
|
+
|
|
48
|
+
[tool.uv]
|
|
49
|
+
# Use: uv sync --extra dev for development. Optional: uv lock for lockfile.
|
|
50
|
+
|
|
51
|
+
[[tool.uv.index]]
|
|
52
|
+
name = "testpypi"
|
|
53
|
+
url = "https://test.pypi.org/simple/"
|
|
54
|
+
publish-url = "https://test.pypi.org/legacy/"
|
|
55
|
+
explicit = true
|
|
56
|
+
|
|
57
|
+
[tool.ruff]
|
|
58
|
+
line-length = 100
|
|
59
|
+
target-version = "py310"
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint]
|
|
62
|
+
select = ["E", "F", "I", "N", "W"]
|
|
63
|
+
ignore = ["E501"]
|
|
64
|
+
|
|
65
|
+
[tool.pytest.ini_options]
|
|
66
|
+
testpaths = ["tests"]
|
|
67
|
+
pythonpath = ["src"]
|
|
68
|
+
addopts = "-v --tb=short"
|
|
69
|
+
|
|
70
|
+
[tool.coverage.run]
|
|
71
|
+
source = ["src/cohorte"]
|
|
72
|
+
branch = true
|
|
73
|
+
|
|
74
|
+
[tool.coverage.report]
|
|
75
|
+
exclude_lines = ["raise NotImplementedError", "if TYPE_CHECKING:"]
|
portazgo-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright 2025 IBM, Red Hat
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
cohorte: Pluggable agent backends for RAGAS dataset generation.
|
|
18
|
+
|
|
19
|
+
Use Agent(type="default") for Llama Stack Responses API, or Agent(type="lang-graph")
|
|
20
|
+
for a future LangGraph-based implementation.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from cohorte.agent import Agent, AgentType
|
|
24
|
+
from cohorte.chats import ChatMessage, format_history_as_prefix
|
|
25
|
+
from cohorte.utils import extract_tool_calls, serialize_for_json, strip_think_blocks
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"Agent",
|
|
29
|
+
"AgentType",
|
|
30
|
+
"ChatMessage",
|
|
31
|
+
"extract_tool_calls",
|
|
32
|
+
"format_history_as_prefix",
|
|
33
|
+
"serialize_for_json",
|
|
34
|
+
"strip_think_blocks",
|
|
35
|
+
]
|
|
36
|
+
__version__ = "0.1.0"
|