acp-sdk 0.12.0__tar.gz → 0.12.2__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.
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/PKG-INFO +1 -1
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/pyproject.toml +1 -1
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/models/models.py +5 -4
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/app.py +23 -12
- acp_sdk-0.12.2/src/acp_sdk/server/resources.py +38 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/.gitignore +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/.python-version +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/README.md +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/docs/.gitignore +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/docs/Makefile +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/docs/conf.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/docs/index.rst +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/docs/make.bat +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/pytest.ini +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/client/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/client/client.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/client/types.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/client/utils.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/instrumentation.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/models/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/models/errors.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/models/platform.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/models/schemas.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/models/types.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/py.typed +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/agent.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/context.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/errors.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/executor.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/logging.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/server.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/store/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/store/memory_store.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/store/postgresql_store.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/store/redis_store.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/store/store.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/store/utils.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/telemetry.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/types.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/server/utils.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/shared/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/shared/resources.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/src/acp_sdk/version.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/conftest.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/config.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/fixtures/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/fixtures/client.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/fixtures/server.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/test_suites/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/test_suites/test_discovery.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/test_suites/test_runs.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/e2e/test_suites/test_sessions.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/unit/client/test_client.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/unit/client/test_utils.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/unit/models/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/unit/models/test_models.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/unit/server/__init__.py +0 -0
- {acp_sdk-0.12.0 → acp_sdk-0.12.2}/tests/unit/server/test_server.py +0 -0
@@ -6,10 +6,11 @@ from enum import Enum
|
|
6
6
|
from typing import Any, Literal, Optional, Union
|
7
7
|
|
8
8
|
from pydantic import AnyUrl, BaseModel, ConfigDict, Field
|
9
|
+
from pydantic.json_schema import SkipJsonSchema
|
9
10
|
|
10
11
|
from acp_sdk.models.errors import ACPError, Error
|
11
12
|
from acp_sdk.models.platform import PlatformUIAnnotation
|
12
|
-
from acp_sdk.models.types import AgentName,
|
13
|
+
from acp_sdk.models.types import AgentName, ResourceUrl, RunId, SessionId
|
13
14
|
from acp_sdk.shared import ResourceLoader, ResourceStore
|
14
15
|
|
15
16
|
|
@@ -336,8 +337,8 @@ class Session(BaseModel):
|
|
336
337
|
history: list[ResourceUrl] = Field(default_factory=list)
|
337
338
|
state: ResourceUrl | None = None
|
338
339
|
|
339
|
-
loader: ResourceLoader | None = Field(None, exclude=True)
|
340
|
-
store: ResourceStore | None = Field(None, exclude=True)
|
340
|
+
loader: SkipJsonSchema[ResourceLoader | None] = Field(None, exclude=True)
|
341
|
+
store: SkipJsonSchema[ResourceStore | None] = Field(None, exclude=True)
|
341
342
|
|
342
343
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
343
344
|
|
@@ -357,6 +358,6 @@ class Session(BaseModel):
|
|
357
358
|
if not store:
|
358
359
|
raise ValueError("Store must be specified")
|
359
360
|
|
360
|
-
id =
|
361
|
+
id = uuid.uuid4()
|
361
362
|
await store.store(id, data)
|
362
363
|
return await store.url(id)
|
@@ -51,6 +51,7 @@ from acp_sdk.server.errors import (
|
|
51
51
|
validation_exception_handler,
|
52
52
|
)
|
53
53
|
from acp_sdk.server.executor import CancelData, Executor, RunData
|
54
|
+
from acp_sdk.server.resources import ServerResourceLoader
|
54
55
|
from acp_sdk.server.store import MemoryStore, Store
|
55
56
|
from acp_sdk.server.utils import stream_sse, wait_util_stop
|
56
57
|
from acp_sdk.shared import ResourceLoader, ResourceStore
|
@@ -161,14 +162,30 @@ def create_app(
|
|
161
162
|
if request.session_id and request.session and request.session_id != request.session.id:
|
162
163
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Session ID mismatch")
|
163
164
|
|
165
|
+
def create_resource_url_forwarded(id: ResourceId) -> ResourceUrl:
|
166
|
+
if not forward_resources:
|
167
|
+
raise RuntimeError("Resource forwarding disabled")
|
168
|
+
return ResourceUrl(url=str(req.url_for("get_resource", resource_id=id)))
|
169
|
+
|
170
|
+
async def create_resource_url(id: ResourceId) -> ResourceUrl:
|
171
|
+
if forward_resources:
|
172
|
+
return create_resource_url_forwarded(id)
|
173
|
+
else:
|
174
|
+
return await resource_store.url(id)
|
175
|
+
|
176
|
+
server_resource_loader = ServerResourceLoader(
|
177
|
+
loader=resource_loader,
|
178
|
+
store=resource_store,
|
179
|
+
create_resource_url=create_resource_url_forwarded if forward_resources else None,
|
180
|
+
)
|
181
|
+
|
164
182
|
session = request.session or (
|
165
|
-
(
|
166
|
-
await session_store.get(request.session_id)
|
167
|
-
or Session(id=request.session_id, loader=resource_loader, store=resource_store)
|
168
|
-
)
|
183
|
+
(await session_store.get(request.session_id) or Session(id=request.session_id))
|
169
184
|
if request.session_id
|
170
|
-
else Session(
|
185
|
+
else Session()
|
171
186
|
)
|
187
|
+
session.loader = server_resource_loader
|
188
|
+
session.store = resource_store
|
172
189
|
|
173
190
|
nonlocal executor
|
174
191
|
run_data = RunData(
|
@@ -183,12 +200,6 @@ def create_app(
|
|
183
200
|
headers = {Headers.RUN_ID: str(run_data.run.run_id)}
|
184
201
|
ready = asyncio.Event()
|
185
202
|
|
186
|
-
async def create_resource_url(id: ResourceId) -> ResourceUrl:
|
187
|
-
if forward_resources:
|
188
|
-
return ResourceUrl(url=str(req.url_for("get_resource", resource_id=id)))
|
189
|
-
else:
|
190
|
-
return await resource_store.url(id)
|
191
|
-
|
192
203
|
Executor(
|
193
204
|
agent=agent,
|
194
205
|
run_data=run_data,
|
@@ -200,7 +211,7 @@ def create_app(
|
|
200
211
|
executor=executor,
|
201
212
|
request=req,
|
202
213
|
resource_store=resource_store,
|
203
|
-
resource_loader=
|
214
|
+
resource_loader=server_resource_loader,
|
204
215
|
create_resource_url=create_resource_url,
|
205
216
|
).execute(request.input, wait=ready)
|
206
217
|
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import re
|
2
|
+
import uuid
|
3
|
+
from typing import Callable
|
4
|
+
|
5
|
+
import cachetools
|
6
|
+
|
7
|
+
from acp_sdk.models import ResourceUrl
|
8
|
+
from acp_sdk.models.types import ResourceId
|
9
|
+
from acp_sdk.shared.resources import ResourceLoader, ResourceStore
|
10
|
+
|
11
|
+
|
12
|
+
class ServerResourceLoader(ResourceLoader):
|
13
|
+
def __init__(
|
14
|
+
self,
|
15
|
+
*,
|
16
|
+
loader: ResourceLoader,
|
17
|
+
store: ResourceStore,
|
18
|
+
create_resource_url: Callable[[ResourceId], ResourceUrl] | None,
|
19
|
+
) -> None:
|
20
|
+
self._loader = loader
|
21
|
+
self._store = store
|
22
|
+
|
23
|
+
placeholder_id = uuid.uuid4()
|
24
|
+
self._url_pattern = (
|
25
|
+
re.escape(str(create_resource_url(placeholder_id))).replace(re.escape(str(placeholder_id)), r"([^/?&#]+)")
|
26
|
+
if create_resource_url
|
27
|
+
else None
|
28
|
+
)
|
29
|
+
|
30
|
+
@cachetools.func.lfu_cache
|
31
|
+
async def load(self, url: ResourceUrl) -> bytes:
|
32
|
+
if self._url_pattern:
|
33
|
+
match = re.match(self._url_pattern, str(url))
|
34
|
+
if match:
|
35
|
+
id = ResourceId(match.group(1))
|
36
|
+
result = await self._store.load(id)
|
37
|
+
return (await result.bytes_async()).to_bytes()
|
38
|
+
return await self._loader.load(url)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|