agentstack-sdk 0.5.2rc2__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.
Files changed (76) hide show
  1. agentstack_sdk/__init__.py +6 -0
  2. agentstack_sdk/a2a/__init__.py +2 -0
  3. agentstack_sdk/a2a/extensions/__init__.py +8 -0
  4. agentstack_sdk/a2a/extensions/auth/__init__.py +5 -0
  5. agentstack_sdk/a2a/extensions/auth/oauth/__init__.py +4 -0
  6. agentstack_sdk/a2a/extensions/auth/oauth/oauth.py +151 -0
  7. agentstack_sdk/a2a/extensions/auth/oauth/storage/__init__.py +5 -0
  8. agentstack_sdk/a2a/extensions/auth/oauth/storage/base.py +11 -0
  9. agentstack_sdk/a2a/extensions/auth/oauth/storage/memory.py +38 -0
  10. agentstack_sdk/a2a/extensions/auth/secrets/__init__.py +4 -0
  11. agentstack_sdk/a2a/extensions/auth/secrets/secrets.py +77 -0
  12. agentstack_sdk/a2a/extensions/base.py +205 -0
  13. agentstack_sdk/a2a/extensions/common/__init__.py +4 -0
  14. agentstack_sdk/a2a/extensions/common/form.py +149 -0
  15. agentstack_sdk/a2a/extensions/exceptions.py +11 -0
  16. agentstack_sdk/a2a/extensions/interactions/__init__.py +4 -0
  17. agentstack_sdk/a2a/extensions/interactions/approval.py +125 -0
  18. agentstack_sdk/a2a/extensions/services/__init__.py +8 -0
  19. agentstack_sdk/a2a/extensions/services/embedding.py +106 -0
  20. agentstack_sdk/a2a/extensions/services/form.py +54 -0
  21. agentstack_sdk/a2a/extensions/services/llm.py +100 -0
  22. agentstack_sdk/a2a/extensions/services/mcp.py +193 -0
  23. agentstack_sdk/a2a/extensions/services/platform.py +141 -0
  24. agentstack_sdk/a2a/extensions/tools/__init__.py +5 -0
  25. agentstack_sdk/a2a/extensions/tools/call.py +114 -0
  26. agentstack_sdk/a2a/extensions/tools/exceptions.py +6 -0
  27. agentstack_sdk/a2a/extensions/ui/__init__.py +10 -0
  28. agentstack_sdk/a2a/extensions/ui/agent_detail.py +54 -0
  29. agentstack_sdk/a2a/extensions/ui/canvas.py +71 -0
  30. agentstack_sdk/a2a/extensions/ui/citation.py +78 -0
  31. agentstack_sdk/a2a/extensions/ui/error.py +223 -0
  32. agentstack_sdk/a2a/extensions/ui/form_request.py +52 -0
  33. agentstack_sdk/a2a/extensions/ui/settings.py +73 -0
  34. agentstack_sdk/a2a/extensions/ui/trajectory.py +70 -0
  35. agentstack_sdk/a2a/types.py +104 -0
  36. agentstack_sdk/platform/__init__.py +12 -0
  37. agentstack_sdk/platform/client.py +123 -0
  38. agentstack_sdk/platform/common.py +37 -0
  39. agentstack_sdk/platform/configuration.py +47 -0
  40. agentstack_sdk/platform/context.py +291 -0
  41. agentstack_sdk/platform/file.py +295 -0
  42. agentstack_sdk/platform/model_provider.py +131 -0
  43. agentstack_sdk/platform/provider.py +219 -0
  44. agentstack_sdk/platform/provider_build.py +190 -0
  45. agentstack_sdk/platform/types.py +45 -0
  46. agentstack_sdk/platform/user.py +70 -0
  47. agentstack_sdk/platform/user_feedback.py +42 -0
  48. agentstack_sdk/platform/variables.py +44 -0
  49. agentstack_sdk/platform/vector_store.py +217 -0
  50. agentstack_sdk/py.typed +0 -0
  51. agentstack_sdk/server/__init__.py +4 -0
  52. agentstack_sdk/server/agent.py +594 -0
  53. agentstack_sdk/server/app.py +87 -0
  54. agentstack_sdk/server/constants.py +9 -0
  55. agentstack_sdk/server/context.py +68 -0
  56. agentstack_sdk/server/dependencies.py +117 -0
  57. agentstack_sdk/server/exceptions.py +3 -0
  58. agentstack_sdk/server/middleware/__init__.py +3 -0
  59. agentstack_sdk/server/middleware/platform_auth_backend.py +131 -0
  60. agentstack_sdk/server/server.py +376 -0
  61. agentstack_sdk/server/store/__init__.py +3 -0
  62. agentstack_sdk/server/store/context_store.py +35 -0
  63. agentstack_sdk/server/store/memory_context_store.py +59 -0
  64. agentstack_sdk/server/store/platform_context_store.py +58 -0
  65. agentstack_sdk/server/telemetry.py +53 -0
  66. agentstack_sdk/server/utils.py +26 -0
  67. agentstack_sdk/types.py +15 -0
  68. agentstack_sdk/util/__init__.py +4 -0
  69. agentstack_sdk/util/file.py +260 -0
  70. agentstack_sdk/util/httpx.py +18 -0
  71. agentstack_sdk/util/logging.py +63 -0
  72. agentstack_sdk/util/resource_context.py +44 -0
  73. agentstack_sdk/util/utils.py +47 -0
  74. agentstack_sdk-0.5.2rc2.dist-info/METADATA +120 -0
  75. agentstack_sdk-0.5.2rc2.dist-info/RECORD +76 -0
  76. agentstack_sdk-0.5.2rc2.dist-info/WHEEL +4 -0
@@ -0,0 +1,260 @@
1
+ # Copyright 2025 © BeeAI a Series of LF Projects, LLC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import base64
5
+ import typing
6
+ from collections.abc import AsyncIterator, Iterator
7
+ from contextlib import AsyncExitStack, asynccontextmanager
8
+ from functools import cached_property
9
+ from typing import Protocol
10
+
11
+ import httpx
12
+ from a2a.types import FilePart, FileWithBytes, FileWithUri
13
+ from httpx._decoders import LineDecoder
14
+ from pydantic import AnyUrl, HttpUrl, RootModel, UrlConstraints
15
+
16
+
17
+ class LoadedFile(Protocol):
18
+ filename: str | None
19
+ content_type: str
20
+ file_size_bytes: int | None
21
+
22
+ @property
23
+ def content(self) -> bytes: ...
24
+ @property
25
+ def text(self) -> str: ...
26
+
27
+ def read(self) -> bytes:
28
+ """
29
+ Read and return the response content.
30
+ """
31
+ ...
32
+
33
+ def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]:
34
+ """
35
+ A byte-iterator over the decoded response content.
36
+ This allows us to handle gzip, deflate, brotli, and zstd encoded responses.
37
+ """
38
+ yield b""
39
+
40
+ def iter_text(self, chunk_size: int | None = None) -> Iterator[str]:
41
+ """
42
+ A str-iterator over the decoded response content
43
+ that handles both gzip, deflate, etc but also detects the content's
44
+ string encoding.
45
+ """
46
+ yield ""
47
+
48
+ def iter_lines(self) -> Iterator[str]:
49
+ yield ""
50
+
51
+ async def aread(self) -> bytes: ...
52
+
53
+ async def aiter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]:
54
+ """
55
+ A byte-iterator over the decoded response content.
56
+ This allows us to handle gzip, deflate, brotli, and zstd encoded responses.
57
+ """
58
+ yield b""
59
+
60
+ async def aiter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]:
61
+ """
62
+ A str-iterator over the decoded response content
63
+ that handles both gzip, deflate, etc but also detects the content's
64
+ string encoding.
65
+ """
66
+ yield ""
67
+
68
+ async def aiter_lines(self) -> AsyncIterator[str]:
69
+ yield ""
70
+
71
+
72
+ class LoadedFileWithBytes(LoadedFile):
73
+ _content: bytes
74
+
75
+ def __init__(
76
+ self,
77
+ content: bytes,
78
+ filename: str | None = None,
79
+ content_type: str | None = None,
80
+ encoding: str | None = None,
81
+ ):
82
+ self.filename = filename
83
+ self.content_type = content_type or "application/octet-stream"
84
+ self.file_size_bytes = len(content)
85
+ self._content = content
86
+ self._encoding = encoding or "utf-8"
87
+
88
+ @property
89
+ def content(self) -> bytes:
90
+ return self._content
91
+
92
+ @cached_property
93
+ def text(self) -> str: # pyright: ignore [reportIncompatibleMethodOverride]
94
+ return self._content.decode(self._encoding)
95
+
96
+ def read(self) -> bytes:
97
+ return b"".join(self.iter_bytes())
98
+
99
+ def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]:
100
+ chunk_size = len(self._content) if chunk_size is None else chunk_size
101
+ for i in range(0, len(self._content), max(chunk_size, 1)):
102
+ yield self._content[i : i + chunk_size]
103
+
104
+ def iter_text(self, chunk_size: int | None = None) -> Iterator[str]:
105
+ chunk_size = len(self._content) if chunk_size is None else chunk_size
106
+ for i in range(0, len(self._content), max(chunk_size, 1)):
107
+ yield self.text[i : i + chunk_size]
108
+
109
+ def iter_lines(self) -> typing.Iterator[str]:
110
+ decoder = LineDecoder()
111
+ for text in self.iter_text():
112
+ for line in decoder.decode(text):
113
+ yield line
114
+ for line in decoder.flush():
115
+ yield line
116
+
117
+ async def aread(self) -> bytes:
118
+ return self._content
119
+
120
+ async def aiter_bytes(self, chunk_size: int | None = None) -> typing.AsyncIterator[bytes]:
121
+ for chunk in self.iter_bytes(chunk_size):
122
+ yield chunk
123
+
124
+ async def aiter_text(self, chunk_size: int | None = None) -> typing.AsyncIterator[str]:
125
+ for chunk in self.iter_text(chunk_size):
126
+ yield chunk
127
+
128
+ async def aiter_lines(self) -> typing.AsyncIterator[str]:
129
+ for line in self.iter_lines():
130
+ yield line
131
+
132
+
133
+ class LoadedFileWithUri:
134
+ _response: httpx.Response # a (potentially still opened) response object
135
+
136
+ def __init__(
137
+ self,
138
+ response: httpx.Response,
139
+ filename: str | None = None,
140
+ content_type: str | None = None,
141
+ file_size_bytes: int | None = None,
142
+ ):
143
+ self._response = response
144
+
145
+ response_filename = self._response.headers.get("Content-Disposition", "").split("filename=")[-1]
146
+ response_content_type = self._response.headers.get("Content-Type", "application/octet-stream")
147
+
148
+ self.file_size_bytes = file_size_bytes or int(response.headers.get("Content-Length", "0")) or None
149
+ self.filename = filename or response_filename
150
+ self.content_type = content_type or response_content_type or "application/octet-stream"
151
+ self._response = response
152
+
153
+ @property
154
+ def content(self) -> bytes:
155
+ return self._response.content
156
+
157
+ @property
158
+ def text(self) -> str:
159
+ return self._response.text
160
+
161
+ def read(self) -> bytes:
162
+ """
163
+ Read and return the response content.
164
+ """
165
+ return self._response.read()
166
+
167
+ def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]:
168
+ """
169
+ A byte-iterator over the decoded response content.
170
+ This allows us to handle gzip, deflate, brotli, and zstd encoded responses.
171
+ """
172
+ yield from self._response.iter_bytes(chunk_size)
173
+
174
+ def iter_text(self, chunk_size: int | None = None) -> Iterator[str]:
175
+ """
176
+ A str-iterator over the decoded response content
177
+ that handles both gzip, deflate, etc but also detects the content's
178
+ string encoding.
179
+ """
180
+ yield from self._response.iter_text(chunk_size)
181
+
182
+ def iter_lines(self) -> Iterator[str]:
183
+ yield from self._response.iter_lines()
184
+
185
+ async def aread(self) -> bytes:
186
+ """
187
+ Read and return the response content.
188
+ """
189
+ return await self._response.aread()
190
+
191
+ async def aiter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]:
192
+ """
193
+ A byte-iterator over the decoded response content.
194
+ This allows us to handle gzip, deflate, brotli, and zstd encoded responses.
195
+ """
196
+ async for chunk in self._response.aiter_bytes(chunk_size):
197
+ yield chunk
198
+
199
+ async def aiter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]:
200
+ """
201
+ A str-iterator over the decoded response content
202
+ that handles both gzip, deflate, etc but also detects the content's
203
+ string encoding.
204
+ """
205
+ async for chunk in self._response.aiter_text(chunk_size):
206
+ yield chunk
207
+
208
+ async def aiter_lines(self) -> AsyncIterator[str]:
209
+ async for line in self._response.aiter_lines():
210
+ yield line
211
+
212
+
213
+ class PlatformFileUrl(AnyUrl):
214
+ _constraints = UrlConstraints(allowed_schemes=["agentstack"])
215
+
216
+ @property
217
+ def file_id(self) -> str:
218
+ assert self.host
219
+ return self.host
220
+
221
+
222
+ UriType = RootModel[PlatformFileUrl | HttpUrl]
223
+
224
+
225
+ @asynccontextmanager
226
+ async def load_file(
227
+ part: FilePart,
228
+ stream: bool = False,
229
+ client: httpx.AsyncClient | None = None,
230
+ ) -> AsyncIterator[LoadedFile]:
231
+ """
232
+ :param stream: if stream is set to False, 'content' and 'text' fields are immediately available.
233
+ Otherwise, they are only available after calling the '(a)read' method.
234
+ """
235
+ match part.file:
236
+ case FileWithUri(mime_type=content_type, name=filename, uri=uri):
237
+ match UriType.model_validate(uri).root:
238
+ case PlatformFileUrl() as url:
239
+ from agentstack_sdk.platform import File
240
+
241
+ async with File.load_content(url.file_id, stream=stream) as file:
242
+ # override filename and content_type from part
243
+ if filename:
244
+ file.filename = filename
245
+ if content_type:
246
+ file.content_type = content_type
247
+ yield file
248
+ case HttpUrl():
249
+ async with AsyncExitStack() as stack:
250
+ if client is None:
251
+ client = await stack.enter_async_context(httpx.AsyncClient())
252
+ async with client.stream("GET", uri) as response:
253
+ response.raise_for_status()
254
+ file = LoadedFileWithUri(response=response, filename=filename, content_type=content_type)
255
+ if not stream:
256
+ await file.aread()
257
+ yield file
258
+
259
+ case FileWithBytes(bytes=content, name=filename, mime_type=content_type):
260
+ yield LoadedFileWithBytes(content=base64.b64decode(content), filename=filename, content_type=content_type)
@@ -0,0 +1,18 @@
1
+ # Copyright 2025 © BeeAI a Series of LF Projects, LLC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+
5
+ import httpx
6
+
7
+
8
+ class BearerAuth(httpx.Auth):
9
+ def __init__(self, token: str):
10
+ self.token = token
11
+
12
+ def auth_flow(self, request: httpx.Request):
13
+ request.headers["Authorization"] = f"Bearer {self.token}"
14
+ yield request
15
+
16
+ async def async_auth_flow(self, request: httpx.Request):
17
+ request.headers["Authorization"] = f"Bearer {self.token}"
18
+ yield request
@@ -0,0 +1,63 @@
1
+ # Copyright 2025 © BeeAI a Series of LF Projects, LLC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import logging
5
+ import logging.config
6
+ import sys
7
+ from logging import getLevelName
8
+ from typing import ClassVar
9
+
10
+ logger = logging.getLogger("agentstack_sdk")
11
+
12
+
13
+ class ColoredFormatter(logging.Formatter):
14
+ COLORS: ClassVar[dict[str, str]] = {
15
+ "DEBUG": "\033[36m", # Cyan
16
+ "INFO": "\033[32m", # Green
17
+ "WARNING": "\033[33m", # Yellow
18
+ "ERROR": "\033[31m", # Red
19
+ "CRITICAL": "\033[35m", # Magenta
20
+ "RESET": "\033[0m", # Reset
21
+ }
22
+
23
+ def format(self, record):
24
+ log_message = super().format(record)
25
+ color = self.COLORS.get(record.levelname, self.COLORS["RESET"])
26
+ reset = self.COLORS["RESET"]
27
+ return f"{color}{log_message}{reset}"
28
+
29
+
30
+ # Dictionary configuration
31
+ LOGGING_CONFIG = {
32
+ "version": 1,
33
+ "disable_existing_loggers": False,
34
+ "formatters": {
35
+ "colored": {
36
+ "()": ColoredFormatter,
37
+ "format": "%(asctime)s | %(levelname)-8s | %(name)-12s | %(message)s",
38
+ "datefmt": "%Y-%m-%d %H:%M:%S",
39
+ },
40
+ "simple": {"format": "%(asctime)s | %(levelname)-8s | %(message)s", "datefmt": "%H:%M:%S"},
41
+ },
42
+ "handlers": {"console": {"class": "logging.StreamHandler", "formatter": "colored", "stream": sys.stdout}},
43
+ "loggers": {
44
+ "root": {"level": "INFO", "handlers": ["console"]},
45
+ "httpx": {"level": "WARNING"},
46
+ "uvicorn": {"handlers": ["console"], "level": "INFO", "propagate": False},
47
+ "uvicorn.error": {"level": "INFO"},
48
+ "uvicorn.access": {"handlers": ["console"], "level": "WARNING", "propagate": False},
49
+ },
50
+ }
51
+
52
+
53
+ def configure_logger(level: int | str | None = None) -> None:
54
+ if level is not None:
55
+ level = level if isinstance(level, int) else logging.getLevelNamesMapping()[level.upper()]
56
+ logging.config.dictConfig(
57
+ {
58
+ **LOGGING_CONFIG,
59
+ "loggers": {"root": {"level": getLevelName(level), "handlers": ["console"]}},
60
+ }
61
+ )
62
+ else:
63
+ logging.config.dictConfig(LOGGING_CONFIG)
@@ -0,0 +1,44 @@
1
+ # Copyright 2025 © BeeAI a Series of LF Projects, LLC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ import contextlib
5
+ import contextvars
6
+ import typing
7
+
8
+
9
+ async def noop():
10
+ pass
11
+
12
+
13
+ P = typing.ParamSpec("P")
14
+ T = typing.TypeVar("T")
15
+
16
+
17
+ def resource_context(
18
+ factory: typing.Callable[P, T],
19
+ default_factory: typing.Callable[[], T],
20
+ ) -> tuple[typing.Callable[[], T], typing.Callable[P, contextlib.AbstractContextManager[T]]]:
21
+ contextvar: contextvars.ContextVar[T] = contextvars.ContextVar(f"resource_context({factory.__name__})")
22
+
23
+ def use_resource(*args: P.args, **kwargs: P.kwargs):
24
+ @contextlib.contextmanager
25
+ def manager():
26
+ resource = factory(*args, **kwargs)
27
+ token = contextvar.set(resource)
28
+ try:
29
+ yield resource
30
+ finally:
31
+ contextvar.reset(token)
32
+
33
+ return manager()
34
+
35
+ def get_resource() -> T:
36
+ try:
37
+ return contextvar.get()
38
+ except LookupError:
39
+ return default_factory()
40
+
41
+ return get_resource, use_resource
42
+
43
+
44
+ __all__ = ["resource_context"]
@@ -0,0 +1,47 @@
1
+ # Copyright 2025 © BeeAI a Series of LF Projects, LLC
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ import json
4
+ import re
5
+ from collections.abc import AsyncIterator
6
+ from datetime import UTC, datetime
7
+ from typing import Any, TypeVar, cast
8
+
9
+ import httpx
10
+ from httpx import HTTPStatusError
11
+
12
+ T = TypeVar("T")
13
+ V = TypeVar("V")
14
+
15
+
16
+ def filter_dict(map: dict[str, T | V], value_to_exclude: V = None) -> dict[str, T]:
17
+ """Remove entries with unwanted values (None by default) from dictionary."""
18
+ return {key: cast(T, value) for key, value in map.items() if value is not value_to_exclude}
19
+
20
+
21
+ async def parse_stream(response: httpx.Response) -> AsyncIterator[dict[str, Any]]:
22
+ if response.is_error:
23
+ error = ""
24
+ try:
25
+ [error] = [json.loads(message) async for message in response.aiter_text()]
26
+ error = error.get("detail", str(error))
27
+ except Exception:
28
+ response.raise_for_status()
29
+ raise HTTPStatusError(message=error, request=response.request, response=response)
30
+ async for line in response.aiter_lines():
31
+ if line:
32
+ data = re.sub("^data:", "", line).strip()
33
+ try:
34
+ yield json.loads(data)
35
+ except json.JSONDecodeError:
36
+ yield {"event": data}
37
+
38
+
39
+ def extract_messages(exc: BaseException) -> list[tuple[str, str]]:
40
+ if isinstance(exc, BaseExceptionGroup):
41
+ return [(exc_type, msg) for e in exc.exceptions for exc_type, msg in extract_messages(e)]
42
+ else:
43
+ return [(type(exc).__name__, str(exc))]
44
+
45
+
46
+ def utc_now() -> datetime:
47
+ return datetime.now(UTC)
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.3
2
+ Name: agentstack-sdk
3
+ Version: 0.5.2rc2
4
+ Summary: Agent Stack SDK
5
+ Author: IBM Corp.
6
+ Requires-Dist: a2a-sdk==0.3.21
7
+ Requires-Dist: objprint>=0.3.0
8
+ Requires-Dist: uvicorn>=0.35.0
9
+ Requires-Dist: asyncclick>=8.1.8
10
+ Requires-Dist: sse-starlette>=2.2.1
11
+ Requires-Dist: starlette>=0.47.2
12
+ Requires-Dist: anyio>=4.9.0
13
+ Requires-Dist: opentelemetry-api>=1.35.0
14
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.35.0
15
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.56b0
16
+ Requires-Dist: opentelemetry-sdk>=1.35.0
17
+ Requires-Dist: tenacity>=9.1.2
18
+ Requires-Dist: janus>=2.0.0
19
+ Requires-Dist: httpx
20
+ Requires-Dist: mcp>=1.12.3
21
+ Requires-Dist: fastapi>=0.116.1
22
+ Requires-Dist: authlib>=1.3.0
23
+ Requires-Dist: async-lru>=2.0.4
24
+ Requires-Python: >=3.11, <3.14
25
+ Description-Content-Type: text/markdown
26
+
27
+ # Agent Stack Server SDK
28
+
29
+ Python SDK for packaging agents for deployment to Agent Stack infrastructure.
30
+
31
+ [![PyPI version](https://img.shields.io/pypi/v/agentstack-sdk.svg?style=plastic)](https://pypi.org/project/agentstack-sdk/)
32
+ [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg?style=plastic)](https://opensource.org/licenses/Apache-2.0)
33
+ [![LF AI & Data](https://img.shields.io/badge/LF%20AI%20%26%20Data-0072C6?style=plastic&logo=linuxfoundation&logoColor=white)](https://lfaidata.foundation/projects/)
34
+
35
+ ## Overview
36
+
37
+ The `agentstack-sdk` provides Python utilities for wrapping agents built with any framework (LangChain, CrewAI, BeeAI Framework, etc.) for deployment on Agent Stack. It handles the A2A (Agent-to-Agent) protocol implementation, platform service integration, and runtime requirements so you can focus on agent logic.
38
+
39
+ ## Key Features
40
+
41
+ - **Framework-Agnostic Deployment** - Wrap agents from any framework for Agent Stack deployment
42
+ - **A2A Protocol Support** - Automatic handling of Agent-to-Agent communication
43
+ - **Platform Service Integration** - Connect to Agent Stack's managed LLM, embedding, file storage, and vector store services
44
+ - **Context Storage** - Manage data associated with conversation contexts
45
+
46
+ ## Installation
47
+
48
+ ```bash
49
+ uv add agentstack-sdk
50
+ ```
51
+
52
+ ## Quickstart
53
+
54
+ ```python
55
+ import os
56
+
57
+ from a2a.types import (
58
+ Message,
59
+ )
60
+ from a2a.utils.message import get_message_text
61
+ from agentstack_sdk.server import Server
62
+ from agentstack_sdk.server.context import RunContext
63
+ from agentstack_sdk.a2a.types import AgentMessage
64
+
65
+ server = Server()
66
+
67
+ @server.agent()
68
+ async def example_agent(input: Message, context: RunContext):
69
+ """Polite agent that greets the user"""
70
+ hello_template: str = os.getenv("HELLO_TEMPLATE", "Ciao %s!")
71
+ yield AgentMessage(text=hello_template % get_message_text(input))
72
+
73
+ def run():
74
+ try:
75
+ server.run(host=os.getenv("HOST", "127.0.0.1"), port=int(os.getenv("PORT", 8000)))
76
+ except KeyboardInterrupt:
77
+ pass
78
+
79
+
80
+ if __name__ == "__main__":
81
+ run()
82
+ ```
83
+
84
+ Run the agent:
85
+
86
+ ```bash
87
+ uv run my_agent.py
88
+ ```
89
+
90
+ ## Available Extensions
91
+
92
+ The SDK includes extension support for:
93
+
94
+ - **Citations** - Source attribution (`CitationExtensionServer`, `CitationExtensionSpec`)
95
+ - **Trajectory** - Agent decision logging (`TrajectoryExtensionServer`, `TrajectoryExtensionSpec`)
96
+ - **Settings** - User-configurable agent parameters (`SettingsExtensionServer`, `SettingsExtensionSpec`)
97
+ - **LLM Services** - Platform-managed language models (`LLMServiceExtensionServer`, `LLMServiceExtensionSpec`)
98
+ - **Agent Details** - Metadata and UI enhancements (`AgentDetail`)
99
+ - **And more** - See [Documentation](https://agentstack.beeai.dev/stable/agent-development/overview)
100
+
101
+ Each extension provides both server-side handlers and A2A protocol specifications for seamless integration with Agent Stack's UI and infrastructure.
102
+
103
+ ## Resources
104
+
105
+ - [Agent Stack Documentation](https://agentstack.beeai.dev)
106
+ - [GitHub Repository](https://github.com/i-am-bee/agentstack)
107
+ - [PyPI Package](https://pypi.org/project/agentstack-sdk/)
108
+
109
+ ## Contributing
110
+
111
+ Contributions are welcome! Please see the [Contributing Guide](https://github.com/i-am-bee/agentstack/blob/main/CONTRIBUTING.md) for details.
112
+
113
+ ## Support
114
+
115
+ - [GitHub Issues](https://github.com/i-am-bee/agentstack/issues)
116
+ - [GitHub Discussions](https://github.com/i-am-bee/agentstack/discussions)
117
+
118
+ ---
119
+
120
+ Developed by contributors to the BeeAI project, this initiative is part of the [Linux Foundation AI & Data program](https://lfaidata.foundation/projects/). Its development follows open, collaborative, and community-driven practices.
@@ -0,0 +1,76 @@
1
+ agentstack_sdk/__init__.py,sha256=PjJzra4hWMfNi_dNOe6n5gasb6NrDQo7apEKxioGxko,174
2
+ agentstack_sdk/a2a/__init__.py,sha256=9xW5VdTorDw2AgBfWH5BrVzjmDbTjKPVsZV86PgsobI,93
3
+ agentstack_sdk/a2a/extensions/__init__.py,sha256=WT_4375xwPvdqcxjZOHG6a9QG1zh2CCyBEevNyJvCD8,205
4
+ agentstack_sdk/a2a/extensions/auth/__init__.py,sha256=Rz8hEJCrWqE2NUUBnjKL1cyNEpI_E58NZuSwgeSgNVE,138
5
+ agentstack_sdk/a2a/extensions/auth/oauth/__init__.py,sha256=iha9SLBVA3V4tRID-bBaxoZq79NIEOMXrNlyGDs2VdQ,115
6
+ agentstack_sdk/a2a/extensions/auth/oauth/oauth.py,sha256=89Y6SexsUY1AxhwN23g9YTUD-AQC_7-LfSe1kA2LP9g,6045
7
+ agentstack_sdk/a2a/extensions/auth/oauth/storage/__init__.py,sha256=TZk5xNltzmEVFedsFaChrfrckGiFHD_T7yyX7ptr_TM,136
8
+ agentstack_sdk/a2a/extensions/auth/oauth/storage/base.py,sha256=QNvijmaYW3LmTrhTDpCimdYtPOCNk0YS21XQRNwSsvc,265
9
+ agentstack_sdk/a2a/extensions/auth/oauth/storage/memory.py,sha256=HWEKqgfMtq3ZJPQrYhYF-Qb3DzUlOfHWHYCladz15QQ,1236
10
+ agentstack_sdk/a2a/extensions/auth/secrets/__init__.py,sha256=K0Dknv6Hpt3CAnqCyRGIs4a6s_6Z0pHLsyERo9jUMGc,117
11
+ agentstack_sdk/a2a/extensions/auth/secrets/secrets.py,sha256=06UygsBiNrWhaRdw8t-nqPnkWKDj0sB2Y-QWtEJuPqc,2802
12
+ agentstack_sdk/a2a/extensions/base.py,sha256=TkwwkDpPITThkTt_vRZwA03S02thLtG9_nFO6euqBIw,7073
13
+ agentstack_sdk/a2a/extensions/common/__init__.py,sha256=3lg8P9ASBFHDipP1oZ3IcPqCAwVFtWr3LMBJzpT0Yqo,114
14
+ agentstack_sdk/a2a/extensions/common/form.py,sha256=tbDD3V-ZW90TjXXkyf3SCQd3zJ3tvbJfJA5cbJuPdH0,3792
15
+ agentstack_sdk/a2a/extensions/exceptions.py,sha256=k4_OFuglnm3XaAr9tl47dNXLLkIhjOQVLohIQ7ieC0M,369
16
+ agentstack_sdk/a2a/extensions/interactions/__init__.py,sha256=GruhHZaI-iMrmzZhkgtb4KOzlVKgnKMYEylfNjIn6_4,118
17
+ agentstack_sdk/a2a/extensions/interactions/approval.py,sha256=DMdiLFEkdgaYyZP-E5pq_tARAn2VNQIIyn_jiZL2RcI,4795
18
+ agentstack_sdk/a2a/extensions/services/__init__.py,sha256=9njkm58sMs_sMQwKGTMkPU-I7c7T99BWy30fcw4nCoI,201
19
+ agentstack_sdk/a2a/extensions/services/embedding.py,sha256=GuvbKaOlZSBn04a7SsIlJrQkehEKnZDxQmJCxpVbf_8,3892
20
+ agentstack_sdk/a2a/extensions/services/form.py,sha256=BmZ-Cqwp4o-j1zgCneuZ_9-1vCOm1OkQMJZLc_Rp1qc,1707
21
+ agentstack_sdk/a2a/extensions/services/llm.py,sha256=pReamcrKU_IkjYn1Ia-dID__PDKUBQiSpRcOSUtIL7s,3644
22
+ agentstack_sdk/a2a/extensions/services/mcp.py,sha256=04wKPvISPsWTVR-YXwd06ajoU6O3VlStGwDDQvEbnKY,7114
23
+ agentstack_sdk/a2a/extensions/services/platform.py,sha256=gImzMBmsQ8ot6sbUWNgW0X_B1fPe6W4UMJhe-LU_8YA,5706
24
+ agentstack_sdk/a2a/extensions/tools/__init__.py,sha256=PWVZLGvw9ZESBfBbSFJuFNcW1SHkCbZi0pj5yt5Uw2g,140
25
+ agentstack_sdk/a2a/extensions/tools/call.py,sha256=JwnlA6K9QJFC0Ca4zSMa2jHDlT0QgcMSu-gJNKejIiU,4288
26
+ agentstack_sdk/a2a/extensions/tools/exceptions.py,sha256=6SmMOjm9ayicfIkdFd0X_vwY7Tqn6M7dNiSF9jpeVeg,148
27
+ agentstack_sdk/a2a/extensions/ui/__init__.py,sha256=pn0blPq1QmquxBOEWaAIzP98ECXnVuLQy4rkhpxzhEg,267
28
+ agentstack_sdk/a2a/extensions/ui/agent_detail.py,sha256=OGKToMFq2FnXI0dRmjXpdaOM3BUPU2YJbA4IZZXr93E,1607
29
+ agentstack_sdk/a2a/extensions/ui/canvas.py,sha256=NAY4R-BjriZJON-79GTD7CfVItl8bNsFfwQCnBQfFAA,2403
30
+ agentstack_sdk/a2a/extensions/ui/citation.py,sha256=TdkIXummv_g9eEuDQfnC4ZjI-BE4umTvctp1471OpdE,2761
31
+ agentstack_sdk/a2a/extensions/ui/error.py,sha256=upZXaq1ZCvv4Ow_ShZGH0-sFYPaiRixanYFZCjzodb4,7393
32
+ agentstack_sdk/a2a/extensions/ui/form_request.py,sha256=YeRiovV3EgqeBD8fHtu_b5qr3negXezxyi6lfFLrqb8,2026
33
+ agentstack_sdk/a2a/extensions/ui/settings.py,sha256=uZu_8u29gAu1H85twFb_LCRBO0jeaEiLgfamaFNUPGM,1814
34
+ agentstack_sdk/a2a/extensions/ui/trajectory.py,sha256=G66rIpr2VTe1UvbK82EgLXwFtUC3QfbyN_uLQGUU8jA,2334
35
+ agentstack_sdk/a2a/types.py,sha256=z1-OxRLIJgYDHwaBJ66MZNIqSTpE1zQ04BPGBGw9IC0,3582
36
+ agentstack_sdk/platform/__init__.py,sha256=jFlxr6P-6DJZVt1W8Xt1suISJpodD_EWX92GmcFLXwM,326
37
+ agentstack_sdk/platform/client.py,sha256=KDN3R1wyoo-ZUYl6ArjRJxre0yAqB0Y6NyKrQpdI268,4234
38
+ agentstack_sdk/platform/common.py,sha256=p6w4l49NaFp7LsjEBDAwghX6FliNChOeO7IHP_-TnXA,750
39
+ agentstack_sdk/platform/configuration.py,sha256=YfOasb6LxE9LN6sMZPEU07Q61F7uIhiU3DIQFRaqinU,1690
40
+ agentstack_sdk/platform/context.py,sha256=vYAQOgZUEelvhP4Sldzt4Y1CP4WVtEE42DSuAMGnn-0,12099
41
+ agentstack_sdk/platform/file.py,sha256=lOqMwMKHKGWFy5P1huQ6DLRTiHU0KexX-s2qF3FIRxw,13062
42
+ agentstack_sdk/platform/model_provider.py,sha256=hv5UbFUFQ23IlalH5W-nCTvnUCrxBtZF4UrkeNWnwFE,4588
43
+ agentstack_sdk/platform/provider.py,sha256=1juAfYc39sVwZ8ZbYz1ohVnzzRacJx6Junvo-7GgVmY,9071
44
+ agentstack_sdk/platform/provider_build.py,sha256=Vn2XDdMGgQWvChWJmg9nxYFVecp42A1jXzURkFgSEQQ,7317
45
+ agentstack_sdk/platform/types.py,sha256=3OHERUoli6t9rlCiaZ2YfN26GXqMQzDFQx_UluCZVYA,1502
46
+ agentstack_sdk/platform/user.py,sha256=ZxTPJYPGxcRtRQJpxPPf2ylz3Erngu2vSMuia1oJ04Q,2148
47
+ agentstack_sdk/platform/user_feedback.py,sha256=IfMzZsaFKpWCPz5MjppDsFLLMM-iVQUBGugz0_FmrqY,1305
48
+ agentstack_sdk/platform/variables.py,sha256=VW7eHO_V6B5I-vvqNgUangkcuUXDcjFIrxUSSfX5cHw,1637
49
+ agentstack_sdk/platform/vector_store.py,sha256=h98RKGuN1SvmfL_bxf3WCLvY1IeQ00Wf7NTP6yr05qg,8695
50
+ agentstack_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
+ agentstack_sdk/server/__init__.py,sha256=vc06L5ILofytmLJC9hJUzA9LakUYUNYGiBoSXNs9hQc,152
52
+ agentstack_sdk/server/agent.py,sha256=tprDvYwsSoImJkMCMVvHKzacH2pWtQUWu19qgWAyNMk,29170
53
+ agentstack_sdk/server/app.py,sha256=1-g_6FBU4lnrBI2KZVnTvsfdKrHyChkeYmJ01iIrj4Y,3396
54
+ agentstack_sdk/server/constants.py,sha256=huQAP351AeNt536tB-axJSseHMHfyDKwJdlackjLGnw,188
55
+ agentstack_sdk/server/context.py,sha256=yBAk3RgBsat1nULzFs2OvF2UKKeNAT8yaSN_s-bcPTU,2712
56
+ agentstack_sdk/server/dependencies.py,sha256=kyUwrIJe99n7UQmqGn_bo--YkPiAR6S9SoeOBwaeW68,5022
57
+ agentstack_sdk/server/exceptions.py,sha256=jr8otByt8HFY9OWptuWdpq4WHE7A1srCSRXZV066FrI,94
58
+ agentstack_sdk/server/middleware/__init__.py,sha256=pEJG3OupRq7IF3O70g2pvDU_EmDF0D3iAuGWXB-_Ipk,94
59
+ agentstack_sdk/server/middleware/platform_auth_backend.py,sha256=h2P4jKJpXOmie1tFU2E5YW-c6-BksINmWEonNUQ5l3g,4986
60
+ agentstack_sdk/server/server.py,sha256=twD5j4Re8rfg63CjcMLJg_tpPBKAkffnP22hTkVS5iY,15909
61
+ agentstack_sdk/server/store/__init__.py,sha256=jr8otByt8HFY9OWptuWdpq4WHE7A1srCSRXZV066FrI,94
62
+ agentstack_sdk/server/store/context_store.py,sha256=ZzXSlxaV_xaTEVDAO0oC0eCiNQve2ydjYUJK3oUAOXA,1060
63
+ agentstack_sdk/server/store/memory_context_store.py,sha256=S604ATyk9wA2D_pZL-Q-I4x01mItKihLJmGwp7bumC4,2346
64
+ agentstack_sdk/server/store/platform_context_store.py,sha256=bv5-sVJUVVblYIAjLsl0_VOqstjfAXWuQgWhewE_9OI,2614
65
+ agentstack_sdk/server/telemetry.py,sha256=MJ5JGF3L_ef8eqx-yguJHgIhbpDtHRSfKm2QKFtlHmI,2014
66
+ agentstack_sdk/server/utils.py,sha256=0s7N-kWEWnPuI2Ki4PZuX5uY48KFLCOHg-lnxRDVEg8,917
67
+ agentstack_sdk/types.py,sha256=1GOt-l2xnJTS_6u37YNoMXkuckX2XwjQ1aH1iv6QRIQ,593
68
+ agentstack_sdk/util/__init__.py,sha256=dCOBqJYOJYvvQSjDZysZGkLxvZV-o9j367ze3jnX_Rc,126
69
+ agentstack_sdk/util/file.py,sha256=rm5b47tHTmJBsHlqGcUqFCP0Bz5HKXPHWW_h-IpG9pw,9035
70
+ agentstack_sdk/util/httpx.py,sha256=g6WKgkGCLc40wZA2CPYO_R2P-nav6QP1XmVlgkh9wYY,491
71
+ agentstack_sdk/util/logging.py,sha256=hGLkjw-P3GefiUQmDmcz7BZQxfT2Y44XlLyAMNxZXMo,2136
72
+ agentstack_sdk/util/resource_context.py,sha256=OmjEXvrLQA6nBkVSBt0n24hNNxJkucd-N32haxJ4Mno,1093
73
+ agentstack_sdk/util/utils.py,sha256=18qFqMRkX4g4eIpvIvLb4FZAs8Q8ojJrpm19oJleb-k,1593
74
+ agentstack_sdk-0.5.2rc2.dist-info/WHEEL,sha256=M6du7VZflc4UPsGphmOXHANdgk8zessdJG0DBUuoA-U,78
75
+ agentstack_sdk-0.5.2rc2.dist-info/METADATA,sha256=FRj4acL7b2M-drk8OH6YgA_a8m8dNOds6jE-WOKiP-A,4433
76
+ agentstack_sdk-0.5.2rc2.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.9.5
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any