fetch-hive-sdk 0.1.0__py3-none-any.whl
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.
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
fetch_hive_sdk — Official Python SDK for the Fetch Hive API.
|
|
3
|
+
|
|
4
|
+
Quick start::
|
|
5
|
+
|
|
6
|
+
from fetch_hive_sdk import FetchHive
|
|
7
|
+
|
|
8
|
+
client = FetchHive(api_key="fhk_...")
|
|
9
|
+
|
|
10
|
+
# Non-streaming
|
|
11
|
+
result = client.invoke_agent(agent="my-agent", message="Hello")
|
|
12
|
+
print(result["response"])
|
|
13
|
+
|
|
14
|
+
# Streaming
|
|
15
|
+
for chunk in client.invoke_agent_stream(agent="my-agent", message="Hello"):
|
|
16
|
+
if chunk.get("type") == "delta":
|
|
17
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .client import FetchHive
|
|
21
|
+
from .streaming import aiter_sse, iter_sse
|
|
22
|
+
|
|
23
|
+
__all__ = ["FetchHive", "iter_sse", "aiter_sse"]
|
fetch_hive_sdk/client.py
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""
|
|
2
|
+
client.py
|
|
3
|
+
|
|
4
|
+
Idiomatic facade for the Fetch Hive API.
|
|
5
|
+
|
|
6
|
+
Usage::
|
|
7
|
+
|
|
8
|
+
from fetch_hive_sdk import FetchHive
|
|
9
|
+
|
|
10
|
+
client = FetchHive(api_key="fhk_...")
|
|
11
|
+
|
|
12
|
+
# Non-streaming prompt
|
|
13
|
+
result = client.invoke_prompt(deployment="my-prompt", inputs={"name": "Alice"})
|
|
14
|
+
print(result["response"])
|
|
15
|
+
|
|
16
|
+
# Streaming agent
|
|
17
|
+
for chunk in client.invoke_agent_stream(agent="my-agent", message="Hello"):
|
|
18
|
+
if chunk.get("type") == "delta":
|
|
19
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
20
|
+
|
|
21
|
+
Async::
|
|
22
|
+
|
|
23
|
+
async for chunk in client.ainvoke_agent_stream(agent="my-agent", message="Hello"):
|
|
24
|
+
...
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import os
|
|
30
|
+
from typing import Any, AsyncIterator, Generator, Iterator
|
|
31
|
+
|
|
32
|
+
import httpx
|
|
33
|
+
|
|
34
|
+
from .streaming import aiter_sse, iter_sse
|
|
35
|
+
|
|
36
|
+
DEFAULT_BASE_URL = "https://api.fetchhive.com/v1"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class FetchHive:
|
|
40
|
+
"""
|
|
41
|
+
Fetch Hive API client.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
api_key: Bearer token from the Fetch Hive dashboard.
|
|
45
|
+
Defaults to the ``FETCH_HIVE_API_KEY`` environment variable.
|
|
46
|
+
base_url: API base URL. Defaults to ``https://api.fetchhive.com/v1``.
|
|
47
|
+
timeout: Request timeout in seconds (default: 120).
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
api_key: str | None = None,
|
|
53
|
+
base_url: str = DEFAULT_BASE_URL,
|
|
54
|
+
timeout: float = 120.0,
|
|
55
|
+
) -> None:
|
|
56
|
+
resolved_key = api_key or os.environ.get("FETCH_HIVE_API_KEY")
|
|
57
|
+
if not resolved_key:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"api_key is required. Pass it explicitly or set the "
|
|
60
|
+
"FETCH_HIVE_API_KEY environment variable."
|
|
61
|
+
)
|
|
62
|
+
self._api_key = resolved_key
|
|
63
|
+
self._base_url = base_url.rstrip("/")
|
|
64
|
+
self._timeout = timeout
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def _headers(self) -> dict[str, str]:
|
|
68
|
+
return {
|
|
69
|
+
"Authorization": f"Bearer {self._api_key}",
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
def _url(self, path: str) -> str:
|
|
74
|
+
return f"{self._base_url}{path}"
|
|
75
|
+
|
|
76
|
+
# ── Prompt ────────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
def invoke_prompt(
|
|
79
|
+
self,
|
|
80
|
+
*,
|
|
81
|
+
deployment: str,
|
|
82
|
+
variant: str = "",
|
|
83
|
+
inputs: dict[str, Any] | None = None,
|
|
84
|
+
user: str | None = None,
|
|
85
|
+
) -> dict[str, Any]:
|
|
86
|
+
"""Invoke a prompt deployment and return the full response."""
|
|
87
|
+
body: dict[str, Any] = {"deployment": deployment, "streaming": False}
|
|
88
|
+
if variant:
|
|
89
|
+
body["variant"] = variant
|
|
90
|
+
if inputs is not None:
|
|
91
|
+
body["inputs"] = inputs
|
|
92
|
+
if user is not None:
|
|
93
|
+
body["user"] = user
|
|
94
|
+
|
|
95
|
+
with httpx.Client(timeout=self._timeout) as client:
|
|
96
|
+
resp = client.post(self._url("/invoke"), headers=self._headers, json=body)
|
|
97
|
+
resp.raise_for_status()
|
|
98
|
+
return resp.json()
|
|
99
|
+
|
|
100
|
+
def invoke_prompt_stream(
|
|
101
|
+
self,
|
|
102
|
+
*,
|
|
103
|
+
deployment: str,
|
|
104
|
+
variant: str = "",
|
|
105
|
+
inputs: dict[str, Any] | None = None,
|
|
106
|
+
user: str | None = None,
|
|
107
|
+
) -> Generator[dict[str, Any], None, None]:
|
|
108
|
+
"""Invoke a prompt deployment and stream SSE events."""
|
|
109
|
+
body: dict[str, Any] = {"deployment": deployment, "streaming": True}
|
|
110
|
+
if variant:
|
|
111
|
+
body["variant"] = variant
|
|
112
|
+
if inputs is not None:
|
|
113
|
+
body["inputs"] = inputs
|
|
114
|
+
if user is not None:
|
|
115
|
+
body["user"] = user
|
|
116
|
+
|
|
117
|
+
with httpx.Client(timeout=self._timeout) as client:
|
|
118
|
+
with client.stream("POST", self._url("/invoke"), headers=self._headers, json=body) as resp:
|
|
119
|
+
yield from iter_sse(resp)
|
|
120
|
+
|
|
121
|
+
async def ainvoke_prompt_stream(
|
|
122
|
+
self,
|
|
123
|
+
*,
|
|
124
|
+
deployment: str,
|
|
125
|
+
variant: str = "",
|
|
126
|
+
inputs: dict[str, Any] | None = None,
|
|
127
|
+
user: str | None = None,
|
|
128
|
+
) -> AsyncIterator[dict[str, Any]]:
|
|
129
|
+
"""Async: invoke a prompt deployment and stream SSE events."""
|
|
130
|
+
body: dict[str, Any] = {"deployment": deployment, "streaming": True}
|
|
131
|
+
if variant:
|
|
132
|
+
body["variant"] = variant
|
|
133
|
+
if inputs is not None:
|
|
134
|
+
body["inputs"] = inputs
|
|
135
|
+
if user is not None:
|
|
136
|
+
body["user"] = user
|
|
137
|
+
|
|
138
|
+
async with httpx.AsyncClient(timeout=self._timeout) as client:
|
|
139
|
+
async with client.stream("POST", self._url("/invoke"), headers=self._headers, json=body) as resp:
|
|
140
|
+
async for chunk in aiter_sse(resp):
|
|
141
|
+
yield chunk
|
|
142
|
+
|
|
143
|
+
# ── Workflow ──────────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
def invoke_workflow(
|
|
146
|
+
self,
|
|
147
|
+
*,
|
|
148
|
+
deployment: str,
|
|
149
|
+
variant: str = "",
|
|
150
|
+
inputs: dict[str, Any] | None = None,
|
|
151
|
+
async_mode: bool = False,
|
|
152
|
+
callback_url: str | None = None,
|
|
153
|
+
user: str | None = None,
|
|
154
|
+
) -> dict[str, Any]:
|
|
155
|
+
"""Invoke a workflow deployment (sync or async)."""
|
|
156
|
+
body: dict[str, Any] = {"deployment": deployment}
|
|
157
|
+
if variant:
|
|
158
|
+
body["variant"] = variant
|
|
159
|
+
if inputs is not None:
|
|
160
|
+
body["inputs"] = inputs
|
|
161
|
+
if user is not None:
|
|
162
|
+
body["user"] = user
|
|
163
|
+
if async_mode:
|
|
164
|
+
body["async"] = {"enabled": True}
|
|
165
|
+
if callback_url:
|
|
166
|
+
body["async"]["callback_url"] = callback_url
|
|
167
|
+
|
|
168
|
+
with httpx.Client(timeout=self._timeout) as client:
|
|
169
|
+
resp = client.post(self._url("/workflow/invoke"), headers=self._headers, json=body)
|
|
170
|
+
resp.raise_for_status()
|
|
171
|
+
return resp.json()
|
|
172
|
+
|
|
173
|
+
# ── Agent ─────────────────────────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
def invoke_agent(
|
|
176
|
+
self,
|
|
177
|
+
*,
|
|
178
|
+
agent: str,
|
|
179
|
+
message: str,
|
|
180
|
+
thread_id: str = "",
|
|
181
|
+
user: str | None = None,
|
|
182
|
+
messages: list[dict[str, Any]] | None = None,
|
|
183
|
+
image_urls: list[str] | None = None,
|
|
184
|
+
) -> dict[str, Any]:
|
|
185
|
+
"""Send a message to an agent and return the full response."""
|
|
186
|
+
body: dict[str, Any] = {"agent": agent, "message": message, "streaming": False}
|
|
187
|
+
if thread_id:
|
|
188
|
+
body["thread_id"] = thread_id
|
|
189
|
+
if user is not None:
|
|
190
|
+
body["user"] = user
|
|
191
|
+
if messages is not None:
|
|
192
|
+
body["messages"] = messages
|
|
193
|
+
if image_urls:
|
|
194
|
+
body["image_urls"] = image_urls
|
|
195
|
+
|
|
196
|
+
with httpx.Client(timeout=self._timeout) as client:
|
|
197
|
+
resp = client.post(self._url("/agent/invoke"), headers=self._headers, json=body)
|
|
198
|
+
resp.raise_for_status()
|
|
199
|
+
return resp.json()
|
|
200
|
+
|
|
201
|
+
def invoke_agent_stream(
|
|
202
|
+
self,
|
|
203
|
+
*,
|
|
204
|
+
agent: str,
|
|
205
|
+
message: str,
|
|
206
|
+
thread_id: str = "",
|
|
207
|
+
user: str | None = None,
|
|
208
|
+
messages: list[dict[str, Any]] | None = None,
|
|
209
|
+
image_urls: list[str] | None = None,
|
|
210
|
+
) -> Generator[dict[str, Any], None, None]:
|
|
211
|
+
"""Send a message to an agent and stream SSE events."""
|
|
212
|
+
body: dict[str, Any] = {"agent": agent, "message": message, "streaming": True}
|
|
213
|
+
if thread_id:
|
|
214
|
+
body["thread_id"] = thread_id
|
|
215
|
+
if user is not None:
|
|
216
|
+
body["user"] = user
|
|
217
|
+
if messages is not None:
|
|
218
|
+
body["messages"] = messages
|
|
219
|
+
if image_urls:
|
|
220
|
+
body["image_urls"] = image_urls
|
|
221
|
+
|
|
222
|
+
with httpx.Client(timeout=self._timeout) as client:
|
|
223
|
+
with client.stream("POST", self._url("/agent/invoke"), headers=self._headers, json=body) as resp:
|
|
224
|
+
yield from iter_sse(resp)
|
|
225
|
+
|
|
226
|
+
async def ainvoke_agent_stream(
|
|
227
|
+
self,
|
|
228
|
+
*,
|
|
229
|
+
agent: str,
|
|
230
|
+
message: str,
|
|
231
|
+
thread_id: str = "",
|
|
232
|
+
user: str | None = None,
|
|
233
|
+
messages: list[dict[str, Any]] | None = None,
|
|
234
|
+
image_urls: list[str] | None = None,
|
|
235
|
+
) -> AsyncIterator[dict[str, Any]]:
|
|
236
|
+
"""Async: send a message to an agent and stream SSE events."""
|
|
237
|
+
body: dict[str, Any] = {"agent": agent, "message": message, "streaming": True}
|
|
238
|
+
if thread_id:
|
|
239
|
+
body["thread_id"] = thread_id
|
|
240
|
+
if user is not None:
|
|
241
|
+
body["user"] = user
|
|
242
|
+
if messages is not None:
|
|
243
|
+
body["messages"] = messages
|
|
244
|
+
if image_urls:
|
|
245
|
+
body["image_urls"] = image_urls
|
|
246
|
+
|
|
247
|
+
async with httpx.AsyncClient(timeout=self._timeout) as client:
|
|
248
|
+
async with client.stream("POST", self._url("/agent/invoke"), headers=self._headers, json=body) as resp:
|
|
249
|
+
async for chunk in aiter_sse(resp):
|
|
250
|
+
yield chunk
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
streaming.py
|
|
3
|
+
|
|
4
|
+
Lightweight Server-Sent Events (SSE) parser for streaming Fetch Hive responses.
|
|
5
|
+
|
|
6
|
+
Provides both synchronous and asynchronous generators.
|
|
7
|
+
|
|
8
|
+
Sync example::
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
from fetch_hive_sdk.streaming import iter_sse
|
|
12
|
+
|
|
13
|
+
with httpx.stream("POST", url, headers=headers, json=body) as response:
|
|
14
|
+
for chunk in iter_sse(response):
|
|
15
|
+
if chunk.get("type") == "delta":
|
|
16
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
17
|
+
|
|
18
|
+
Async example::
|
|
19
|
+
|
|
20
|
+
import httpx
|
|
21
|
+
from fetch_hive_sdk.streaming import aiter_sse
|
|
22
|
+
|
|
23
|
+
async with httpx.AsyncClient() as client:
|
|
24
|
+
async with client.stream("POST", url, headers=headers, json=body) as response:
|
|
25
|
+
async for chunk in aiter_sse(response):
|
|
26
|
+
if chunk.get("type") == "delta":
|
|
27
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import json
|
|
33
|
+
from typing import Any, AsyncIterator, Generator, Iterator
|
|
34
|
+
|
|
35
|
+
import httpx
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _parse_line(line: str) -> dict[str, Any] | None:
|
|
39
|
+
"""Parse a single SSE data line. Returns None for non-data lines or [DONE]."""
|
|
40
|
+
if not line.startswith("data: "):
|
|
41
|
+
return None
|
|
42
|
+
payload = line[6:]
|
|
43
|
+
if payload.strip() == "[DONE]":
|
|
44
|
+
return None
|
|
45
|
+
try:
|
|
46
|
+
return json.loads(payload)
|
|
47
|
+
except json.JSONDecodeError:
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def iter_sse(response: httpx.Response) -> Generator[dict[str, Any], None, None]:
|
|
52
|
+
"""
|
|
53
|
+
Synchronous generator that yields parsed SSE events from an httpx streaming
|
|
54
|
+
response.
|
|
55
|
+
|
|
56
|
+
Stops at ``data: [DONE]``.
|
|
57
|
+
"""
|
|
58
|
+
response.raise_for_status()
|
|
59
|
+
buf = ""
|
|
60
|
+
for chunk in response.iter_text():
|
|
61
|
+
buf += chunk
|
|
62
|
+
while "\n" in buf:
|
|
63
|
+
line, buf = buf.split("\n", 1)
|
|
64
|
+
line = line.rstrip("\r")
|
|
65
|
+
event = _parse_line(line)
|
|
66
|
+
if event is None and line.strip() == "data: [DONE]":
|
|
67
|
+
return
|
|
68
|
+
if event is not None:
|
|
69
|
+
yield event
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def aiter_sse(response: httpx.Response) -> AsyncIterator[dict[str, Any]]:
|
|
73
|
+
"""
|
|
74
|
+
Asynchronous generator that yields parsed SSE events from an httpx streaming
|
|
75
|
+
response.
|
|
76
|
+
|
|
77
|
+
Stops at ``data: [DONE]``.
|
|
78
|
+
"""
|
|
79
|
+
response.raise_for_status()
|
|
80
|
+
buf = ""
|
|
81
|
+
async for chunk in response.aiter_text():
|
|
82
|
+
buf += chunk
|
|
83
|
+
while "\n" in buf:
|
|
84
|
+
line, buf = buf.split("\n", 1)
|
|
85
|
+
line = line.rstrip("\r")
|
|
86
|
+
if line.strip() == "data: [DONE]":
|
|
87
|
+
return
|
|
88
|
+
event = _parse_line(line)
|
|
89
|
+
if event is not None:
|
|
90
|
+
yield event
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fetch-hive-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for the Fetch Hive API
|
|
5
|
+
Project-URL: Homepage, https://fetchhive.com
|
|
6
|
+
Project-URL: Repository, https://github.com/Fetch-Hive/python-sdk
|
|
7
|
+
Project-URL: Documentation, https://docs.fetchhive.com
|
|
8
|
+
Author-email: Fetch Hive <hello@fetchhive.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: agents,ai,fetchhive,sdk,workflows
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Requires-Dist: httpx>=0.25.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: respx>=0.20; extra == 'dev'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# fetch-hive-sdk
|
|
28
|
+
|
|
29
|
+
Official Python SDK for [Fetch Hive](https://fetchhive.com) — invoke AI prompts, workflows, and agents from your application.
|
|
30
|
+
|
|
31
|
+
[](https://pypi.org/project/fetch-hive-sdk/)
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install fetch-hive-sdk
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from fetch_hive_sdk import FetchHive
|
|
43
|
+
|
|
44
|
+
client = FetchHive(api_key="fhk_...")
|
|
45
|
+
# or: client = FetchHive() # reads FETCH_HIVE_API_KEY env var
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Get your API key from the [Fetch Hive dashboard](https://app.fetchhive.com).
|
|
49
|
+
|
|
50
|
+
## Invoke a prompt
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
result = client.invoke_prompt(
|
|
54
|
+
deployment="my-prompt",
|
|
55
|
+
inputs={"name": "Alice", "topic": "machine learning"},
|
|
56
|
+
)
|
|
57
|
+
print(result["response"])
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Invoke a prompt (streaming)
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
for chunk in client.invoke_prompt_stream(
|
|
64
|
+
deployment="my-prompt",
|
|
65
|
+
inputs={"name": "Alice"},
|
|
66
|
+
):
|
|
67
|
+
if chunk.get("type") == "delta":
|
|
68
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Invoke a workflow
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
run = client.invoke_workflow(
|
|
75
|
+
deployment="my-workflow",
|
|
76
|
+
inputs={"customer_id": "42"},
|
|
77
|
+
)
|
|
78
|
+
print(run["status"], run.get("output"))
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Async workflow
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
run = client.invoke_workflow(
|
|
85
|
+
deployment="my-workflow",
|
|
86
|
+
inputs={"customer_id": "42"},
|
|
87
|
+
async_mode=True,
|
|
88
|
+
callback_url="https://example.com/webhook",
|
|
89
|
+
)
|
|
90
|
+
print("Queued:", run["run_id"])
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Invoke an agent (streaming)
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
for chunk in client.invoke_agent_stream(
|
|
97
|
+
agent="my-agent",
|
|
98
|
+
message="What is the weather in London?",
|
|
99
|
+
thread_id="session-abc123", # optional — persist conversation history
|
|
100
|
+
):
|
|
101
|
+
if chunk.get("type") == "delta":
|
|
102
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
103
|
+
elif chunk.get("type") == "tool_start":
|
|
104
|
+
print(f"\n[Calling tool: {chunk.get('tool_name')}]")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Async streaming
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
import asyncio
|
|
111
|
+
|
|
112
|
+
async def main():
|
|
113
|
+
async for chunk in client.ainvoke_agent_stream(
|
|
114
|
+
agent="my-agent",
|
|
115
|
+
message="Hello",
|
|
116
|
+
):
|
|
117
|
+
if chunk.get("type") == "delta":
|
|
118
|
+
print(chunk.get("content", ""), end="", flush=True)
|
|
119
|
+
|
|
120
|
+
asyncio.run(main())
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Multimodal (image) inputs
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
result = client.invoke_agent(
|
|
127
|
+
agent="vision-agent",
|
|
128
|
+
message="Describe this image",
|
|
129
|
+
image_urls=["https://example.com/photo.jpg"],
|
|
130
|
+
)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Authentication
|
|
134
|
+
|
|
135
|
+
Pass the API key to the constructor or set the `FETCH_HIVE_API_KEY` environment variable:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
export FETCH_HIVE_API_KEY=fhk_...
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Version
|
|
142
|
+
|
|
143
|
+
0.1.0
|
|
144
|
+
|
|
145
|
+
## License
|
|
146
|
+
|
|
147
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
fetch_hive_sdk/__init__.py,sha256=nFoBWeMW9G80tblzOglIBi8RSQxCyyyDstn7fmUbE6E,616
|
|
2
|
+
fetch_hive_sdk/client.py,sha256=OZVWuGLNZp-nqBYB2z3dAgyz3SKyk7QOloqxiyEm2_g,8815
|
|
3
|
+
fetch_hive_sdk/streaming.py,sha256=gdaF0pSYxKnD1-hdTNSynNi9o4KAktLgjB6_8ZbCsHs,2599
|
|
4
|
+
fetch_hive_sdk-0.1.0.dist-info/METADATA,sha256=7i7DjvMJg-pvKaYaiJyouFZ8cXYnKFXsJZQ9S5NFAGw,3561
|
|
5
|
+
fetch_hive_sdk-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
6
|
+
fetch_hive_sdk-0.1.0.dist-info/RECORD,,
|