acp-sdk 0.12.2__tar.gz → 0.13.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.
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/PKG-INFO +1 -1
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/pyproject.toml +1 -1
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/client/client.py +5 -12
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/models/models.py +28 -1
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/server.py +7 -7
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/test_suites/test_sessions.py +15 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/unit/client/test_client.py +10 -5
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/.gitignore +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/.python-version +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/README.md +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/docs/.gitignore +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/docs/Makefile +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/docs/conf.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/docs/index.rst +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/docs/make.bat +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/pytest.ini +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/client/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/client/types.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/client/utils.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/instrumentation.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/models/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/models/errors.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/models/platform.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/models/schemas.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/models/types.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/py.typed +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/agent.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/app.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/context.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/errors.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/executor.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/logging.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/resources.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/store/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/store/memory_store.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/store/postgresql_store.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/store/redis_store.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/store/store.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/store/utils.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/telemetry.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/types.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/server/utils.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/shared/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/shared/resources.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/src/acp_sdk/version.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/conftest.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/config.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/fixtures/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/fixtures/client.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/fixtures/server.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/test_suites/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/test_suites/test_discovery.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/e2e/test_suites/test_runs.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/unit/client/test_utils.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/unit/models/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/unit/models/test_models.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/unit/server/__init__.py +0 -0
- {acp_sdk-0.12.2 → acp_sdk-0.13.0}/tests/unit/server/test_server.py +0 -0
@@ -252,15 +252,10 @@ class Client:
|
|
252
252
|
base_url=base_url or self._session_last_refresh_base_url,
|
253
253
|
)
|
254
254
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
except ACPError as e:
|
260
|
-
if e.error.code == ErrorCode.NOT_FOUND:
|
261
|
-
pass
|
262
|
-
raise e
|
263
|
-
|
255
|
+
response = await self._client.get(url, timeout=timeout)
|
256
|
+
self._raise_error(response)
|
257
|
+
response = SessionReadResponse.model_validate(response.json())
|
258
|
+
self._session = Session(**response.model_dump())
|
264
259
|
return self._session
|
265
260
|
|
266
261
|
async def _validate_stream(
|
@@ -304,13 +299,11 @@ class Client:
|
|
304
299
|
|
305
300
|
target_base_url = self._create_base_url(base_url=base_url)
|
306
301
|
try:
|
307
|
-
if not self._session_last_refresh_base_url:
|
308
|
-
return {"session": self._session}
|
309
302
|
if self._session_last_refresh_base_url == target_base_url:
|
310
303
|
# Same server, no need to forward session
|
311
304
|
return {"session_id": self._session.id}
|
312
305
|
|
313
|
-
session = await self.refresh_session()
|
306
|
+
session = await self.refresh_session(base_url=self._session_last_refresh_base_url or target_base_url)
|
314
307
|
return {"session": session}
|
315
308
|
except ACPError as e:
|
316
309
|
if e.error.code == ErrorCode.NOT_FOUND:
|
@@ -118,6 +118,33 @@ class CitationMetadata(BaseModel):
|
|
118
118
|
description: Optional[str]
|
119
119
|
|
120
120
|
|
121
|
+
class TrajectoryMetadata(BaseModel):
|
122
|
+
"""
|
123
|
+
Represents trajectory information for an agent's reasoning or tool execution
|
124
|
+
steps. This metadata helps track the agent's decision-making process and
|
125
|
+
provides transparency into how the agent arrived at its response.
|
126
|
+
|
127
|
+
TrajectoryMetadata can capture either:
|
128
|
+
1. A reasoning step with a message
|
129
|
+
2. A tool execution with tool name, input, and output
|
130
|
+
|
131
|
+
This information can be used for debugging, audit trails, and providing
|
132
|
+
users with insight into the agent's thought process.
|
133
|
+
|
134
|
+
Properties:
|
135
|
+
- message: A reasoning step or thought in the agent's decision process.
|
136
|
+
- tool_name: Name of the tool that was executed.
|
137
|
+
- tool_input: Input parameters passed to the tool.
|
138
|
+
- tool_output: Output or result returned by the tool.
|
139
|
+
"""
|
140
|
+
|
141
|
+
kind: Literal["trajectory"] = "trajectory"
|
142
|
+
message: Optional[str] = None
|
143
|
+
tool_name: Optional[str] = None
|
144
|
+
tool_input: Optional[AnyModel] = None
|
145
|
+
tool_output: Optional[AnyModel] = None
|
146
|
+
|
147
|
+
|
121
148
|
class MessagePart(BaseModel):
|
122
149
|
name: Optional[str] = None
|
123
150
|
content_type: Optional[str] = "text/plain"
|
@@ -127,7 +154,7 @@ class MessagePart(BaseModel):
|
|
127
154
|
|
128
155
|
model_config = ConfigDict(extra="allow")
|
129
156
|
|
130
|
-
metadata: Optional[CitationMetadata] = Field(discriminator="kind", default=None)
|
157
|
+
metadata: Optional[CitationMetadata | TrajectoryMetadata] = Field(discriminator="kind", default=None)
|
131
158
|
|
132
159
|
def model_post_init(self, __context: Any) -> None:
|
133
160
|
if self.content is not None and self.content_url is not None:
|
@@ -331,14 +331,14 @@ class Server:
|
|
331
331
|
request_data = {
|
332
332
|
"location": f"http://{host}:{self.server.config.port}",
|
333
333
|
}
|
334
|
-
await async_request_with_retry(lambda client, data=request_data: client.get(f"{url}/api/v1/providers"))
|
335
334
|
try:
|
335
|
+
await async_request_with_retry(lambda client, data=request_data: client.get(f"{url}/api/v1/providers"))
|
336
336
|
await async_request_with_retry(
|
337
337
|
lambda client, data=request_data: client.post(
|
338
338
|
f"{url}/api/v1/providers", json=data, params={"auto_remove": True}
|
339
339
|
)
|
340
340
|
)
|
341
|
-
logger.
|
341
|
+
logger.debug("Agent registered to the beeai server.")
|
342
342
|
|
343
343
|
# check missing env keyes
|
344
344
|
envs_request = await async_request_with_retry(lambda client: client.get(f"{url}/api/v1/variables"))
|
@@ -361,17 +361,17 @@ class Server:
|
|
361
361
|
elif env.get("required"):
|
362
362
|
missing_keyes.append(env)
|
363
363
|
if len(missing_keyes):
|
364
|
-
logger.
|
364
|
+
logger.debug(f"Can not run agent, missing required env variables: {missing_keyes}")
|
365
365
|
raise Exception("Missing env variables")
|
366
366
|
|
367
367
|
except requests.exceptions.ConnectionError as e:
|
368
|
-
logger.
|
368
|
+
logger.debug(f"Can not reach server, check if running on {url} : {e}")
|
369
369
|
except (requests.exceptions.HTTPError, Exception) as e:
|
370
370
|
try:
|
371
371
|
error_message = e.response.json().get("detail")
|
372
372
|
if error_message:
|
373
|
-
logger.
|
373
|
+
logger.debug(f"Agent can not be registered to beeai server: {error_message}")
|
374
374
|
else:
|
375
|
-
logger.
|
375
|
+
logger.debug(f"Agent can not be registered to beeai server: {e}")
|
376
376
|
except Exception:
|
377
|
-
logger.
|
377
|
+
logger.debug(f"Agent can not be registered to beeai server: {e}")
|
@@ -6,6 +6,7 @@ from acp_sdk.models import (
|
|
6
6
|
Message,
|
7
7
|
MessagePart,
|
8
8
|
)
|
9
|
+
from acp_sdk.models.models import Session
|
9
10
|
from acp_sdk.server import Server
|
10
11
|
|
11
12
|
agent = "history_echo"
|
@@ -31,6 +32,20 @@ async def test_session_refresh(server: Server, client: Client) -> None:
|
|
31
32
|
assert len(sess.history) == len(input) * 2
|
32
33
|
|
33
34
|
|
35
|
+
@pytest.mark.asyncio
|
36
|
+
async def test_session_multi_client(server: Server, client: Client) -> None:
|
37
|
+
session = Session()
|
38
|
+
|
39
|
+
async with client.session(session) as session_client:
|
40
|
+
run = await session_client.run_sync(input, agent=agent)
|
41
|
+
assert run.output == output
|
42
|
+
print(run.session_id)
|
43
|
+
|
44
|
+
async with client.session(session) as session_client:
|
45
|
+
run = await session_client.run_sync(input, agent=agent)
|
46
|
+
assert run.output == output * 3
|
47
|
+
|
48
|
+
|
34
49
|
@pytest.mark.asyncio
|
35
50
|
async def test_distributed_session(multi_server: tuple[Server, Server]) -> None:
|
36
51
|
one, two = multi_server
|
@@ -176,23 +176,28 @@ async def test_run_events(httpx_mock: HTTPXMock) -> None:
|
|
176
176
|
@pytest.mark.asyncio
|
177
177
|
async def test_session(httpx_mock: HTTPXMock) -> None:
|
178
178
|
httpx_mock.add_response(url="http://test/runs", method="POST", content=mock_run.model_dump_json(), is_reusable=True)
|
179
|
+
httpx_mock.add_response(
|
180
|
+
url=f"http://test/sessions/{mock_session.id}",
|
181
|
+
method="GET",
|
182
|
+
content=mock_session.model_dump_json(),
|
183
|
+
is_reusable=True,
|
184
|
+
)
|
179
185
|
|
180
|
-
async with Client(base_url="http://test") as client, client.session(
|
181
|
-
assert session._session.id == mock_run.session_id
|
186
|
+
async with Client(base_url="http://test") as client, client.session(mock_session) as session:
|
182
187
|
await session.run_sync("Howdy!", agent=mock_run.agent_name)
|
183
188
|
await session.run_sync("Howdy!", agent=mock_run.agent_name)
|
184
189
|
await client.run_sync("Howdy!", agent=mock_run.agent_name)
|
185
190
|
|
186
191
|
requests = httpx_mock.get_requests()
|
187
|
-
body = json.loads(requests[
|
192
|
+
body = json.loads(requests[1].content)
|
188
193
|
# First request gets full session
|
189
194
|
assert body["session"]["id"] == str(mock_run.session_id)
|
190
195
|
|
191
|
-
body = json.loads(requests[
|
196
|
+
body = json.loads(requests[2].content)
|
192
197
|
# Second sends just the ID
|
193
198
|
assert body["session_id"] == str(mock_run.session_id)
|
194
199
|
|
195
|
-
body = json.loads(requests[
|
200
|
+
body = json.loads(requests[3].content)
|
196
201
|
assert body["session_id"] is None
|
197
202
|
assert body["session"] is None
|
198
203
|
|
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
|