acp-sdk 0.2.3__tar.gz → 0.2.5__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.
Files changed (43) hide show
  1. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/PKG-INFO +1 -1
  2. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/pyproject.toml +1 -1
  3. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/client/client.py +21 -12
  4. acp_sdk-0.2.5/src/acp_sdk/instrumentation.py +7 -0
  5. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/bundle.py +3 -1
  6. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/errors.py +3 -1
  7. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/telemetry.py +0 -4
  8. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/fixtures/server.py +2 -2
  9. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/.gitignore +0 -0
  10. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/.python-version +0 -0
  11. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/README.md +0 -0
  12. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/clients/advanced.py +0 -0
  13. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/clients/session.py +0 -0
  14. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/clients/simple.py +0 -0
  15. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/clients/stream.py +0 -0
  16. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/servers/awaiting.py +0 -0
  17. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/servers/echo.py +0 -0
  18. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/examples/servers/standalone.py +0 -0
  19. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/pytest.ini +0 -0
  20. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/__init__.py +0 -0
  21. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/client/__init__.py +0 -0
  22. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/models/__init__.py +0 -0
  23. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/models/errors.py +0 -0
  24. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/models/models.py +0 -0
  25. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/models/schemas.py +0 -0
  26. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/py.typed +0 -0
  27. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/__init__.py +0 -0
  28. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/agent.py +0 -0
  29. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/app.py +0 -0
  30. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/context.py +0 -0
  31. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/logging.py +0 -0
  32. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/server.py +0 -0
  33. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/session.py +0 -0
  34. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/types.py +0 -0
  35. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/server/utils.py +0 -0
  36. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/src/acp_sdk/version.py +0 -0
  37. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/conftest.py +0 -0
  38. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/__init__.py +0 -0
  39. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/config.py +0 -0
  40. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/fixtures/__init__.py +0 -0
  41. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/fixtures/client.py +0 -0
  42. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/test_suites/__init__.py +0 -0
  43. {acp_sdk-0.2.3 → acp_sdk-0.2.5}/tests/e2e/test_suites/test_runs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: acp-sdk
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: Agent Communication Protocol SDK
5
5
  Author: IBM Corp.
6
6
  Maintainer-email: Tomas Pilar <thomas7pilar@gmail.com>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "acp-sdk"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "Agent Communication Protocol SDK"
5
5
  license = "Apache-2.0"
6
6
  readme = "README.md"
@@ -9,6 +9,7 @@ from httpx_sse import EventSource, aconnect_sse
9
9
  from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
10
10
  from pydantic import TypeAdapter
11
11
 
12
+ from acp_sdk.instrumentation import get_tracer
12
13
  from acp_sdk.models import (
13
14
  ACPError,
14
15
  Agent,
@@ -37,17 +38,20 @@ class Client:
37
38
  self,
38
39
  *,
39
40
  base_url: httpx.URL | str = "",
41
+ timeout: httpx.Timeout | None = None,
40
42
  session_id: SessionId | None = None,
41
43
  client: httpx.AsyncClient | None = None,
42
44
  instrument: bool = True,
43
45
  ) -> None:
44
- self.base_url = base_url
45
- self.session_id = session_id
46
-
47
- self._client = client or httpx.AsyncClient(base_url=self.base_url)
46
+ self._session_id = session_id
47
+ self._client = client or httpx.AsyncClient(base_url=base_url, timeout=timeout)
48
48
  if instrument:
49
49
  HTTPXClientInstrumentor.instrument_client(self._client)
50
50
 
51
+ @property
52
+ def client(self) -> httpx.AsyncClient:
53
+ return self._client
54
+
51
55
  async def __aenter__(self) -> Self:
52
56
  await self._client.__aenter__()
53
57
  return self
@@ -62,7 +66,9 @@ class Client:
62
66
 
63
67
  @asynccontextmanager
64
68
  async def session(self, session_id: SessionId | None = None) -> AsyncGenerator[Self]:
65
- yield Client(client=self._client, session_id=session_id or uuid.uuid4(), instrument=False)
69
+ session_id = session_id or uuid.uuid4()
70
+ with get_tracer().start_as_current_span("session", attributes={"acp.session": str(session_id)}):
71
+ yield Client(client=self._client, session_id=session_id, instrument=False)
66
72
 
67
73
  async def agents(self) -> AsyncIterator[Agent]:
68
74
  response = await self._client.get("/agents")
@@ -82,7 +88,7 @@ class Client:
82
88
  agent_name=agent,
83
89
  inputs=inputs,
84
90
  mode=RunMode.SYNC,
85
- session_id=self.session_id,
91
+ session_id=self._session_id,
86
92
  ).model_dump_json(),
87
93
  )
88
94
  self._raise_error(response)
@@ -97,7 +103,7 @@ class Client:
97
103
  agent_name=agent,
98
104
  inputs=inputs,
99
105
  mode=RunMode.ASYNC,
100
- session_id=self.session_id,
106
+ session_id=self._session_id,
101
107
  ).model_dump_json(),
102
108
  )
103
109
  self._raise_error(response)
@@ -114,7 +120,7 @@ class Client:
114
120
  agent_name=agent,
115
121
  inputs=inputs,
116
122
  mode=RunMode.STREAM,
117
- session_id=self.session_id,
123
+ session_id=self._session_id,
118
124
  ).model_dump_json(),
119
125
  ) as event_source:
120
126
  async for event in self._validate_stream(event_source):
@@ -135,7 +141,7 @@ class Client:
135
141
  async def run_resume_sync(self, *, run_id: RunId, await_resume: AwaitResume) -> Run:
136
142
  response = await self._client.post(
137
143
  f"/runs/{run_id}",
138
- json=RunResumeRequest(await_resume=await_resume, mode=RunMode.SYNC).model_dump(),
144
+ content=RunResumeRequest(await_resume=await_resume, mode=RunMode.SYNC).model_dump_json(),
139
145
  )
140
146
  self._raise_error(response)
141
147
  return RunResumeResponse.model_validate(response.json())
@@ -143,7 +149,7 @@ class Client:
143
149
  async def run_resume_async(self, *, run_id: RunId, await_resume: AwaitResume) -> Run:
144
150
  response = await self._client.post(
145
151
  f"/runs/{run_id}",
146
- json=RunResumeRequest(await_resume=await_resume, mode=RunMode.ASYNC).model_dump(),
152
+ content=RunResumeRequest(await_resume=await_resume, mode=RunMode.ASYNC).model_dump_json(),
147
153
  )
148
154
  self._raise_error(response)
149
155
  return RunResumeResponse.model_validate(response.json())
@@ -153,7 +159,7 @@ class Client:
153
159
  self._client,
154
160
  "POST",
155
161
  f"/runs/{run_id}",
156
- json=RunResumeRequest(await_resume=await_resume, mode=RunMode.STREAM).model_dump(),
162
+ content=RunResumeRequest(await_resume=await_resume, mode=RunMode.STREAM).model_dump_json(),
157
163
  ) as event_source:
158
164
  async for event in self._validate_stream(event_source):
159
165
  yield event
@@ -162,6 +168,9 @@ class Client:
162
168
  self,
163
169
  event_source: EventSource,
164
170
  ) -> AsyncIterator[Event]:
171
+ if event_source.response.is_error:
172
+ await event_source.response.aread()
173
+ self._raise_error(event_source.response)
165
174
  async for event in event_source.aiter_sse():
166
175
  event = TypeAdapter(Event).validate_json(event.data)
167
176
  yield event
@@ -173,4 +182,4 @@ class Client:
173
182
  raise ACPError(Error.model_validate(response.json()))
174
183
 
175
184
  def _set_session(self, run: Run) -> None:
176
- self.session_id = run.session_id
185
+ self._session_id = run.session_id
@@ -0,0 +1,7 @@
1
+ from opentelemetry import trace
2
+
3
+ from acp_sdk.version import __version__
4
+
5
+
6
+ def get_tracer() -> trace.Tracer:
7
+ return trace.get_tracer("acp-sdk", __version__)
@@ -5,6 +5,7 @@ from concurrent.futures import ThreadPoolExecutor
5
5
 
6
6
  from pydantic import ValidationError
7
7
 
8
+ from acp_sdk.instrumentation import get_tracer
8
9
  from acp_sdk.models import (
9
10
  ACPError,
10
11
  AnyModel,
@@ -30,7 +31,6 @@ from acp_sdk.models import (
30
31
  )
31
32
  from acp_sdk.server.agent import Agent
32
33
  from acp_sdk.server.logging import logger
33
- from acp_sdk.server.telemetry import get_tracer
34
34
 
35
35
 
36
36
  class RunBundle:
@@ -127,6 +127,8 @@ class RunBundle:
127
127
  await_resume = await self.await_()
128
128
  await self.emit(RunInProgressEvent(run=self.run))
129
129
  run_logger.info("Run resumed")
130
+ elif isinstance(next, Error):
131
+ raise ACPError(error=next)
130
132
  else:
131
133
  try:
132
134
  generic = AnyModel.model_validate(next)
@@ -32,7 +32,9 @@ def status_code_to_error_code(status_code: int) -> ErrorCode:
32
32
 
33
33
  async def acp_error_handler(request: Request, exc: ACPError, *, status_code: int | None = None) -> JSONResponse:
34
34
  error = exc.error
35
- return JSONResponse(status_code=status_code or error_code_to_status_code(error.code), content=error.model_dump())
35
+ return JSONResponse(
36
+ status_code=status_code or error_code_to_status_code(error.code), content=error.model_dump_json()
37
+ )
36
38
 
37
39
 
38
40
  async def http_exception_handler(request: Request, exc: StarletteHTTPException) -> JSONResponse:
@@ -51,7 +51,3 @@ def configure_telemetry() -> None:
51
51
  processor = BatchLogRecordProcessor(OTLPLogExporter())
52
52
  logger_provider.add_log_record_processor(processor)
53
53
  root_logger.addHandler(LoggingHandler(logger_provider=logger_provider))
54
-
55
-
56
- def get_tracer() -> trace.Tracer:
57
- return trace.get_tracer("acp-sdk", __version__)
@@ -4,7 +4,7 @@ from collections.abc import AsyncGenerator, AsyncIterator, Generator
4
4
  from threading import Thread
5
5
 
6
6
  import pytest
7
- from acp_sdk.models import ACPError, Artifact, AwaitRequest, AwaitResume, Error, ErrorCode, Message, MessagePart
7
+ from acp_sdk.models import Artifact, AwaitRequest, AwaitResume, Error, ErrorCode, Message, MessagePart
8
8
  from acp_sdk.server import Context, Server
9
9
 
10
10
  from e2e.config import Config
@@ -26,7 +26,7 @@ def server() -> Generator[None]:
26
26
 
27
27
  @server.agent()
28
28
  async def failer(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
29
- raise ACPError(Error(code=ErrorCode.INVALID_INPUT, message="Wrong question buddy!"))
29
+ yield Error(code=ErrorCode.INVALID_INPUT, message="Wrong question buddy!")
30
30
 
31
31
  @server.agent()
32
32
  async def sessioner(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
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