acp-sdk 1.0.0rc3__tar.gz → 1.0.0rc4__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 (37) hide show
  1. acp_sdk-1.0.0rc4/PKG-INFO +78 -0
  2. acp_sdk-1.0.0rc4/README.md +59 -0
  3. acp_sdk-1.0.0rc4/examples/servers/awaiting.py +23 -0
  4. acp_sdk-1.0.0rc4/examples/servers/echo.py +24 -0
  5. acp_sdk-1.0.0rc4/examples/servers/sync_echo.py +16 -0
  6. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/pyproject.toml +3 -1
  7. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/models/__init__.py +1 -0
  8. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/models/models.py +0 -36
  9. acp_sdk-1.0.0rc4/src/acp_sdk/models/schemas.py +39 -0
  10. acp_sdk-1.0.0rc4/src/acp_sdk/server/__init__.py +8 -0
  11. acp_sdk-1.0.0rc4/src/acp_sdk/server/agent.py +74 -0
  12. acp_sdk-1.0.0rc3/src/acp_sdk/server/server.py → acp_sdk-1.0.0rc4/src/acp_sdk/server/app.py +15 -18
  13. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/server/bundle.py +5 -2
  14. acp_sdk-1.0.0rc4/src/acp_sdk/server/context.py +26 -0
  15. acp_sdk-1.0.0rc4/src/acp_sdk/server/server.py +110 -0
  16. acp_sdk-1.0.0rc4/src/acp_sdk/server/types.py +6 -0
  17. acp_sdk-1.0.0rc3/PKG-INFO +0 -51
  18. acp_sdk-1.0.0rc3/README.md +0 -33
  19. acp_sdk-1.0.0rc3/examples/servers/awaiting.py +0 -28
  20. acp_sdk-1.0.0rc3/examples/servers/echo.py +0 -29
  21. acp_sdk-1.0.0rc3/src/acp_sdk/server/__init__.py +0 -3
  22. acp_sdk-1.0.0rc3/src/acp_sdk/server/agent.py +0 -35
  23. acp_sdk-1.0.0rc3/src/acp_sdk/server/context.py +0 -6
  24. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/.gitignore +0 -0
  25. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/.python-version +0 -0
  26. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/examples/clients/advanced.py +0 -0
  27. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/examples/clients/simple.py +0 -0
  28. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/examples/clients/stream.py +0 -0
  29. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/__init__.py +0 -0
  30. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/client/__init__.py +0 -0
  31. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/client/client.py +0 -0
  32. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/models/errors.py +0 -0
  33. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/py.typed +0 -0
  34. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/server/errors.py +0 -0
  35. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/server/logging.py +0 -0
  36. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/server/telemetry.py +0 -0
  37. {acp_sdk-1.0.0rc3 → acp_sdk-1.0.0rc4}/src/acp_sdk/server/utils.py +0 -0
@@ -0,0 +1,78 @@
1
+ Metadata-Version: 2.4
2
+ Name: acp-sdk
3
+ Version: 1.0.0rc4
4
+ Summary: Agent Communication Protocol SDK
5
+ Requires-Python: <4.0,>=3.11
6
+ Requires-Dist: opentelemetry-api>=1.31.1
7
+ Requires-Dist: pydantic>=2.11.1
8
+ Provides-Extra: client
9
+ Requires-Dist: httpx-sse>=0.4.0; extra == 'client'
10
+ Requires-Dist: httpx>=0.28.1; extra == 'client'
11
+ Requires-Dist: opentelemetry-instrumentation-httpx>=0.52b1; extra == 'client'
12
+ Provides-Extra: server
13
+ Requires-Dist: fastapi[standard]>=0.115.8; extra == 'server'
14
+ Requires-Dist: janus>=2.0.0; extra == 'server'
15
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.31.1; extra == 'server'
16
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.52b1; extra == 'server'
17
+ Requires-Dist: opentelemetry-sdk>=1.31.1; extra == 'server'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # Agent Communication Protocol SDK for Python
21
+
22
+ Agent Communication Protocol SDK for Python provides allows developers to serve and consume agents over the Agent Communication Protocol.
23
+
24
+ ## Prerequisites
25
+
26
+ ✅ Python >= 3.11
27
+
28
+ ## Installation
29
+
30
+ Install to use client:
31
+
32
+ ```shell
33
+ pip install acp-sdk[client]
34
+ ```
35
+
36
+ Install to use server:
37
+
38
+ ```shell
39
+ pip install acp-sdk[server]
40
+ ```
41
+
42
+ ## Overview
43
+
44
+ ### Client
45
+
46
+ The `client` submodule exposes [httpx]() based client with simple methods for communication over ACP.
47
+
48
+ ```python
49
+ async with Client(base_url="http://localhost:8000") as client:
50
+ run = await client.run_sync(agent="echo", input=Message(TextMessagePart(content="Howdy!")))
51
+ print(run.output)
52
+ ```
53
+
54
+ ### Server
55
+
56
+ The `server` submodule exposes [fastapi] application factory that makes it easy to expose any agent over ACP.
57
+
58
+ ```python
59
+ class EchoAgent(Agent):
60
+ @property
61
+ def name(self) -> str:
62
+ return "echo"
63
+
64
+ @property
65
+ def description(self) -> str:
66
+ return "Echoes everything"
67
+
68
+ async def run(self, input: Message, *, context: Context) -> AsyncGenerator[Message | Await, AwaitResume]:
69
+ for part in input:
70
+ await asyncio.sleep(0.5)
71
+ yield {"thought": "I should echo everyting"}
72
+ yield Message(part)
73
+
74
+
75
+ serve(EchoAgent())
76
+ ```
77
+
78
+ ➡️ Explore more in our [examples library](/python/examples).
@@ -0,0 +1,59 @@
1
+ # Agent Communication Protocol SDK for Python
2
+
3
+ Agent Communication Protocol SDK for Python provides allows developers to serve and consume agents over the Agent Communication Protocol.
4
+
5
+ ## Prerequisites
6
+
7
+ ✅ Python >= 3.11
8
+
9
+ ## Installation
10
+
11
+ Install to use client:
12
+
13
+ ```shell
14
+ pip install acp-sdk[client]
15
+ ```
16
+
17
+ Install to use server:
18
+
19
+ ```shell
20
+ pip install acp-sdk[server]
21
+ ```
22
+
23
+ ## Overview
24
+
25
+ ### Client
26
+
27
+ The `client` submodule exposes [httpx]() based client with simple methods for communication over ACP.
28
+
29
+ ```python
30
+ async with Client(base_url="http://localhost:8000") as client:
31
+ run = await client.run_sync(agent="echo", input=Message(TextMessagePart(content="Howdy!")))
32
+ print(run.output)
33
+ ```
34
+
35
+ ### Server
36
+
37
+ The `server` submodule exposes [fastapi] application factory that makes it easy to expose any agent over ACP.
38
+
39
+ ```python
40
+ class EchoAgent(Agent):
41
+ @property
42
+ def name(self) -> str:
43
+ return "echo"
44
+
45
+ @property
46
+ def description(self) -> str:
47
+ return "Echoes everything"
48
+
49
+ async def run(self, input: Message, *, context: Context) -> AsyncGenerator[Message | Await, AwaitResume]:
50
+ for part in input:
51
+ await asyncio.sleep(0.5)
52
+ yield {"thought": "I should echo everyting"}
53
+ yield Message(part)
54
+
55
+
56
+ serve(EchoAgent())
57
+ ```
58
+
59
+ ➡️ Explore more in our [examples library](/python/examples).
@@ -0,0 +1,23 @@
1
+ from collections.abc import AsyncGenerator
2
+ from typing import Any
3
+
4
+ from acp_sdk.models import (
5
+ Await,
6
+ AwaitResume,
7
+ Message,
8
+ TextMessagePart,
9
+ )
10
+ from acp_sdk.server import Context, Server
11
+
12
+ server = Server()
13
+
14
+
15
+ @server.agent()
16
+ async def awaiting(input: Message, context: Context) -> AsyncGenerator[Message | Await | Any, AwaitResume]:
17
+ """Greets and awaits for more data"""
18
+ yield Message(TextMessagePart(content="Hello!"))
19
+ data = yield Await()
20
+ yield Message(TextMessagePart(content=f"Thanks for {data}"))
21
+
22
+
23
+ server.run()
@@ -0,0 +1,24 @@
1
+ import asyncio
2
+ from collections.abc import AsyncGenerator
3
+ from typing import Any
4
+
5
+ from acp_sdk.models import (
6
+ Await,
7
+ AwaitResume,
8
+ Message,
9
+ )
10
+ from acp_sdk.server import Context, Server
11
+
12
+ server = Server()
13
+
14
+
15
+ @server.agent()
16
+ async def echo(input: Message, context: Context) -> AsyncGenerator[Message | Await | Any, AwaitResume]:
17
+ """Echoes everything"""
18
+ for part in input:
19
+ await asyncio.sleep(0.5)
20
+ yield {"thought": "I should echo everyting"}
21
+ yield Message(part)
22
+
23
+
24
+ server.run()
@@ -0,0 +1,16 @@
1
+ from acp_sdk.models import (
2
+ Message,
3
+ )
4
+ from acp_sdk.server import RunYield, Server, SyncContext
5
+
6
+ server = Server()
7
+
8
+
9
+ @server.agent()
10
+ def echo(input: Message, context: SyncContext) -> RunYield:
11
+ """Echoes everything"""
12
+ context.yield_({"thought": "I should echo everyting"})
13
+ return input
14
+
15
+
16
+ server.run()
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "acp-sdk"
3
- version = "1.0.0rc3"
3
+ version = "1.0.0rc4"
4
4
  description = "Agent Communication Protocol SDK"
5
5
  readme = "README.md"
6
6
  authors = []
@@ -18,6 +18,7 @@ server = [
18
18
  "opentelemetry-exporter-otlp-proto-http>=1.31.1",
19
19
  "opentelemetry-instrumentation-fastapi>=0.52b1",
20
20
  "opentelemetry-sdk>=1.31.1",
21
+ "janus>=2.0.0",
21
22
  ]
22
23
 
23
24
  [tool.uv]
@@ -29,6 +30,7 @@ dev-dependencies = [
29
30
  "opentelemetry-exporter-otlp-proto-http>=1.31.1",
30
31
  "opentelemetry-instrumentation-fastapi>=0.52b1",
31
32
  "opentelemetry-sdk>=1.31.1",
33
+ "janus>=2.0.0",
32
34
  ]
33
35
 
34
36
  [build-system]
@@ -1,2 +1,3 @@
1
1
  from acp_sdk.models.errors import * # noqa: F403
2
2
  from acp_sdk.models.models import * # noqa: F403
3
+ from acp_sdk.models.schemas import * # noqa: F403
@@ -175,43 +175,7 @@ RunEvent = Union[
175
175
  ]
176
176
 
177
177
 
178
- class RunCreateRequest(BaseModel):
179
- agent_name: AgentName
180
- session_id: SessionId | None = None
181
- input: Message
182
- mode: RunMode = RunMode.SYNC
183
-
184
-
185
- class RunCreateResponse(Run):
186
- pass
187
-
188
-
189
- class RunResumeRequest(BaseModel):
190
- await_: AwaitResume = Field(alias="await")
191
- mode: RunMode
192
-
193
-
194
- class RunResumeResponse(Run):
195
- pass
196
-
197
-
198
- class RunReadResponse(Run):
199
- pass
200
-
201
-
202
- class RunCancelResponse(Run):
203
- pass
204
-
205
-
206
178
  class Agent(BaseModel):
207
179
  name: str
208
180
  description: str | None = None
209
181
  metadata: Metadata = Metadata()
210
-
211
-
212
- class AgentsListResponse(BaseModel):
213
- agents: list[Agent]
214
-
215
-
216
- class AgentReadResponse(Agent):
217
- pass
@@ -0,0 +1,39 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+ from acp_sdk.models.models import Agent, AgentName, AwaitResume, Message, Run, RunMode, SessionId
4
+
5
+
6
+ class AgentsListResponse(BaseModel):
7
+ agents: list[Agent]
8
+
9
+
10
+ class AgentReadResponse(Agent):
11
+ pass
12
+
13
+
14
+ class RunCreateRequest(BaseModel):
15
+ agent_name: AgentName
16
+ session_id: SessionId | None = None
17
+ input: Message
18
+ mode: RunMode = RunMode.SYNC
19
+
20
+
21
+ class RunCreateResponse(Run):
22
+ pass
23
+
24
+
25
+ class RunResumeRequest(BaseModel):
26
+ await_: AwaitResume = Field(alias="await")
27
+ mode: RunMode
28
+
29
+
30
+ class RunResumeResponse(Run):
31
+ pass
32
+
33
+
34
+ class RunReadResponse(Run):
35
+ pass
36
+
37
+
38
+ class RunCancelResponse(Run):
39
+ pass
@@ -0,0 +1,8 @@
1
+ from acp_sdk.server.agent import Agent as Agent
2
+ from acp_sdk.server.agent import SyncAgent as SyncAgent
3
+ from acp_sdk.server.app import create_app as create_app
4
+ from acp_sdk.server.context import Context as Context
5
+ from acp_sdk.server.context import SyncContext as SyncContext
6
+ from acp_sdk.server.server import Server as Server
7
+ from acp_sdk.server.types import RunYield as RunYield
8
+ from acp_sdk.server.types import RunYieldResume as RunYieldResume
@@ -0,0 +1,74 @@
1
+ import abc
2
+ import asyncio
3
+ from collections.abc import AsyncGenerator
4
+ from concurrent.futures import ThreadPoolExecutor
5
+
6
+ import janus
7
+
8
+ from acp_sdk.models import (
9
+ AgentName,
10
+ Message,
11
+ SessionId,
12
+ )
13
+ from acp_sdk.models.models import Metadata
14
+ from acp_sdk.server.context import Context, SyncContext
15
+ from acp_sdk.server.types import RunYield, RunYieldResume
16
+
17
+
18
+ class Agent(abc.ABC):
19
+ @property
20
+ def name(self) -> AgentName:
21
+ return self.__class__.__name__
22
+
23
+ @property
24
+ def description(self) -> str:
25
+ return ""
26
+
27
+ @property
28
+ def metadata(self) -> Metadata:
29
+ return Metadata()
30
+
31
+ @abc.abstractmethod
32
+ def run(
33
+ self, input: Message, context: Context, executor: ThreadPoolExecutor
34
+ ) -> AsyncGenerator[RunYield, RunYieldResume]:
35
+ pass
36
+
37
+ async def session(self, session_id: SessionId | None) -> SessionId | None:
38
+ if session_id:
39
+ raise NotImplementedError()
40
+ return None
41
+
42
+
43
+ class SyncAgent(Agent):
44
+ @abc.abstractmethod
45
+ def run_sync(self, input: Message, context: SyncContext, executor: ThreadPoolExecutor) -> RunYield | None:
46
+ pass
47
+
48
+ async def run(
49
+ self, input: Message, context: Context, executor: ThreadPoolExecutor
50
+ ) -> AsyncGenerator[RunYield, RunYieldResume]:
51
+ yield_queue: janus.Queue[RunYield] = janus.Queue()
52
+ yield_resume_queue: janus.Queue[RunYieldResume] = janus.Queue()
53
+
54
+ run_future = asyncio.get_running_loop().run_in_executor(
55
+ executor,
56
+ self.run_sync,
57
+ input,
58
+ SyncContext(
59
+ session_id=context.session_id,
60
+ yield_queue=yield_queue.sync_q,
61
+ yield_resume_queue=yield_resume_queue.sync_q,
62
+ ),
63
+ executor,
64
+ )
65
+
66
+ while True:
67
+ yield_task = asyncio.create_task(yield_queue.async_q.get())
68
+ done, _ = await asyncio.wait([yield_task, run_future], return_when=asyncio.FIRST_COMPLETED)
69
+ if yield_task in done:
70
+ resume = yield await yield_task
71
+ await yield_resume_queue.async_q.put(resume)
72
+ if run_future in done:
73
+ yield await run_future
74
+ break
@@ -1,5 +1,7 @@
1
1
  import asyncio
2
- from typing import Any
2
+ from collections.abc import AsyncGenerator
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ from contextlib import asynccontextmanager
3
5
 
4
6
  from fastapi import FastAPI, HTTPException, status
5
7
  from fastapi.responses import JSONResponse, StreamingResponse
@@ -34,13 +36,20 @@ from acp_sdk.server.errors import (
34
36
  http_exception_handler,
35
37
  validation_exception_handler,
36
38
  )
37
- from acp_sdk.server.logging import configure_logger as configure_logger_func
38
- from acp_sdk.server.telemetry import configure_telemetry as configure_telemetry_func
39
39
  from acp_sdk.server.utils import stream_sse
40
40
 
41
41
 
42
42
  def create_app(*agents: Agent) -> FastAPI:
43
- app = FastAPI(title="acp-agents")
43
+ executor: ThreadPoolExecutor
44
+
45
+ @asynccontextmanager
46
+ async def lifespan(app: FastAPI) -> AsyncGenerator[None]:
47
+ nonlocal executor
48
+ with ThreadPoolExecutor(max_workers=5) as exec:
49
+ executor = exec
50
+ yield
51
+
52
+ app = FastAPI(lifespan=lifespan)
44
53
 
45
54
  FastAPIInstrumentor.instrument_app(app)
46
55
 
@@ -89,7 +98,8 @@ def create_app(*agents: Agent) -> FastAPI:
89
98
  ),
90
99
  )
91
100
 
92
- bundle.task = asyncio.create_task(bundle.execute(request.input))
101
+ nonlocal executor
102
+ bundle.task = asyncio.create_task(bundle.execute(request.input, executor=executor))
93
103
  runs[bundle.run.run_id] = bundle
94
104
 
95
105
  match request.mode:
@@ -149,16 +159,3 @@ def create_app(*agents: Agent) -> FastAPI:
149
159
  return JSONResponse(status_code=status.HTTP_202_ACCEPTED, content=bundle.run.model_dump())
150
160
 
151
161
  return app
152
-
153
-
154
- def serve(
155
- *agents: Agent, configure_logger: bool = True, configure_telemetry: bool = False, **kwargs: dict[str, Any]
156
- ) -> None:
157
- import uvicorn
158
-
159
- if configure_logger:
160
- configure_logger_func()
161
- if configure_telemetry:
162
- configure_telemetry_func()
163
-
164
- uvicorn.run(create_app(*agents), **kwargs)
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import logging
3
3
  from collections.abc import AsyncGenerator
4
+ from concurrent.futures import ThreadPoolExecutor
4
5
 
5
6
  from opentelemetry import trace
6
7
  from pydantic import ValidationError
@@ -68,7 +69,7 @@ class RunBundle:
68
69
  async def join(self) -> None:
69
70
  await self.await_or_terminate_event.wait()
70
71
 
71
- async def execute(self, input: Message) -> None:
72
+ async def execute(self, input: Message, *, executor: ThreadPoolExecutor) -> None:
72
73
  with trace.get_tracer(__name__).start_as_current_span("execute"):
73
74
  run_logger = logging.LoggerAdapter(logger, {"run_id": self.run.run_id})
74
75
 
@@ -77,7 +78,9 @@ class RunBundle:
77
78
  self.run.session_id = await self.agent.session(self.run.session_id)
78
79
  run_logger.info("Session loaded")
79
80
 
80
- generator = self.agent.run(input=input, context=Context(session_id=self.run.session_id))
81
+ generator = self.agent.run(
82
+ input=input, context=Context(session_id=self.run.session_id), executor=executor
83
+ )
81
84
  run_logger.info("Run started")
82
85
 
83
86
  self.run.status = RunStatus.IN_PROGRESS
@@ -0,0 +1,26 @@
1
+ import janus
2
+
3
+ from acp_sdk.models import SessionId
4
+ from acp_sdk.server.types import RunYield, RunYieldResume
5
+
6
+
7
+ class Context:
8
+ def __init__(self, *, session_id: SessionId | None = None) -> None:
9
+ self.session_id = session_id
10
+
11
+
12
+ class SyncContext(Context):
13
+ def __init__(
14
+ self,
15
+ *,
16
+ session_id: SessionId | None = None,
17
+ yield_queue: janus.SyncQueue[RunYield],
18
+ yield_resume_queue: janus.SyncQueue[RunYieldResume],
19
+ ) -> None:
20
+ super().__init__(session_id=session_id)
21
+ self._yield_queue = yield_queue
22
+ self._yield_resume_queue = yield_resume_queue
23
+
24
+ def yield_(self, data: RunYield) -> RunYieldResume:
25
+ self._yield_queue.put(data)
26
+ return self._yield_resume_queue.get()
@@ -0,0 +1,110 @@
1
+ import inspect
2
+ from collections.abc import AsyncGenerator
3
+ from concurrent.futures import ThreadPoolExecutor
4
+ from typing import Any, Callable
5
+
6
+ from acp_sdk.models import Message
7
+ from acp_sdk.server.agent import Agent, SyncAgent
8
+ from acp_sdk.server.app import create_app
9
+ from acp_sdk.server.context import Context
10
+ from acp_sdk.server.logging import configure_logger as configure_logger_func
11
+ from acp_sdk.server.telemetry import configure_telemetry as configure_telemetry_func
12
+ from acp_sdk.server.types import RunYield, RunYieldResume
13
+
14
+
15
+ class Server:
16
+ def __init__(self) -> None:
17
+ self.agents: list[Agent] = []
18
+
19
+ def agent(self, name: str | None = None, description: str | None = None) -> Callable:
20
+ """Decorator to register an agent."""
21
+
22
+ def decorator(fn: Callable) -> Callable:
23
+ # check agent's function signature
24
+ signature = inspect.signature(fn)
25
+ parameters = list(signature.parameters.values())
26
+
27
+ # validate agent's function
28
+ if inspect.isasyncgenfunction(fn):
29
+ if len(parameters) != 2:
30
+ raise TypeError(
31
+ "The agent generator function must have one 'input' argument and one 'context' argument"
32
+ )
33
+ else:
34
+ if len(parameters) != 2:
35
+ raise TypeError("The agent function must have one 'input' argument and one 'context' argument")
36
+
37
+ agent: Agent
38
+ if inspect.isasyncgenfunction(fn):
39
+
40
+ class DecoratedAgent(Agent):
41
+ @property
42
+ def name(self) -> str:
43
+ return name or fn.__name__
44
+
45
+ @property
46
+ def description(self) -> str:
47
+ return description or fn.__doc__ or ""
48
+
49
+ async def run(
50
+ self, input: Message, context: Context, executor: ThreadPoolExecutor
51
+ ) -> AsyncGenerator[RunYield, RunYieldResume]:
52
+ gen: AsyncGenerator[RunYield, RunYieldResume] = fn(input, context)
53
+ value = None
54
+ while True:
55
+ try:
56
+ value = yield await gen.asend(value)
57
+ except StopAsyncIteration:
58
+ break
59
+
60
+ agent = DecoratedAgent()
61
+ elif inspect.iscoroutinefunction(fn):
62
+
63
+ class DecoratedAgent(Agent):
64
+ @property
65
+ def name(self) -> str:
66
+ return name or fn.__name__
67
+
68
+ @property
69
+ def description(self) -> str:
70
+ return description or fn.__doc__ or ""
71
+
72
+ async def run(
73
+ self, input: Message, context: Context, executor: ThreadPoolExecutor
74
+ ) -> AsyncGenerator[RunYield, RunYieldResume]:
75
+ yield await fn(input, context)
76
+
77
+ agent = DecoratedAgent()
78
+ else:
79
+
80
+ class DecoratedAgent(SyncAgent):
81
+ @property
82
+ def name(self) -> str:
83
+ return name or fn.__name__
84
+
85
+ @property
86
+ def description(self) -> str:
87
+ return description or fn.__doc__ or ""
88
+
89
+ def run_sync(self, input: Message, context: Context, executor: ThreadPoolExecutor) -> None:
90
+ return fn(input, context)
91
+
92
+ agent = DecoratedAgent()
93
+
94
+ self.register(agent)
95
+ return fn
96
+
97
+ return decorator
98
+
99
+ def register(self, *agents: Agent) -> None:
100
+ self.agents.extend(agents)
101
+
102
+ def run(self, configure_logger: bool = True, configure_telemetry: bool = False, **kwargs: dict[str, Any]) -> None:
103
+ import uvicorn
104
+
105
+ if configure_logger:
106
+ configure_logger_func()
107
+ if configure_telemetry:
108
+ configure_telemetry_func()
109
+
110
+ uvicorn.run(create_app(*self.agents), **kwargs)
@@ -0,0 +1,6 @@
1
+ from typing import Any
2
+
3
+ from acp_sdk.models import Await, AwaitResume, Message
4
+
5
+ RunYield = Message | Await | dict[str | Any]
6
+ RunYieldResume = AwaitResume | None
acp_sdk-1.0.0rc3/PKG-INFO DELETED
@@ -1,51 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: acp-sdk
3
- Version: 1.0.0rc3
4
- Summary: Agent Communication Protocol SDK
5
- Requires-Python: <4.0,>=3.11
6
- Requires-Dist: opentelemetry-api>=1.31.1
7
- Requires-Dist: pydantic>=2.11.1
8
- Provides-Extra: client
9
- Requires-Dist: httpx-sse>=0.4.0; extra == 'client'
10
- Requires-Dist: httpx>=0.28.1; extra == 'client'
11
- Requires-Dist: opentelemetry-instrumentation-httpx>=0.52b1; extra == 'client'
12
- Provides-Extra: server
13
- Requires-Dist: fastapi[standard]>=0.115.8; extra == 'server'
14
- Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.31.1; extra == 'server'
15
- Requires-Dist: opentelemetry-instrumentation-fastapi>=0.52b1; extra == 'server'
16
- Requires-Dist: opentelemetry-sdk>=1.31.1; extra == 'server'
17
- Description-Content-Type: text/markdown
18
-
19
- # Agent Communication Protocol SDK for Python
20
-
21
- ## Prerequisites
22
-
23
- ✅ Python >= 3.13
24
-
25
- ## Installation
26
-
27
- Install using pip:
28
-
29
- ```shell
30
- pip install acp-sdk
31
- ```
32
-
33
- ## Examples
34
-
35
- The SDK can be used to implement both clients and servers.
36
-
37
- ### Server
38
-
39
- ```shell
40
- python examples/servers/echo.py
41
- ```
42
-
43
- ### Client
44
-
45
- To run an example client:
46
-
47
- ```shell
48
- python examples/clients/simple.py
49
- ```
50
-
51
- ➡️ Explore more in our [examples library](/python/examples).
@@ -1,33 +0,0 @@
1
- # Agent Communication Protocol SDK for Python
2
-
3
- ## Prerequisites
4
-
5
- ✅ Python >= 3.13
6
-
7
- ## Installation
8
-
9
- Install using pip:
10
-
11
- ```shell
12
- pip install acp-sdk
13
- ```
14
-
15
- ## Examples
16
-
17
- The SDK can be used to implement both clients and servers.
18
-
19
- ### Server
20
-
21
- ```shell
22
- python examples/servers/echo.py
23
- ```
24
-
25
- ### Client
26
-
27
- To run an example client:
28
-
29
- ```shell
30
- python examples/clients/simple.py
31
- ```
32
-
33
- ➡️ Explore more in our [examples library](/python/examples).
@@ -1,28 +0,0 @@
1
- from collections.abc import AsyncGenerator
2
-
3
- from acp_sdk.models import (
4
- Await,
5
- AwaitResume,
6
- Message,
7
- TextMessagePart,
8
- )
9
- from acp_sdk.server import Agent, serve
10
- from acp_sdk.server.context import Context
11
-
12
-
13
- class AwaitingAgent(Agent):
14
- @property
15
- def name(self) -> str:
16
- return "awaiting"
17
-
18
- @property
19
- def description(self) -> str:
20
- return "Greets and awaits for more data"
21
-
22
- async def run(self, input: Message, *, context: Context) -> AsyncGenerator[Message | Await, AwaitResume]:
23
- yield Message(TextMessagePart(content="Hello!"))
24
- data = yield Await()
25
- yield Message(TextMessagePart(content=f"Thanks for {data}"))
26
-
27
-
28
- serve(AwaitingAgent())
@@ -1,29 +0,0 @@
1
- import asyncio
2
- from collections.abc import AsyncGenerator
3
-
4
- from acp_sdk.models import (
5
- Await,
6
- AwaitResume,
7
- Message,
8
- )
9
- from acp_sdk.server import Agent, serve
10
- from acp_sdk.server.context import Context
11
-
12
-
13
- class EchoAgent(Agent):
14
- @property
15
- def name(self) -> str:
16
- return "echo"
17
-
18
- @property
19
- def description(self) -> str:
20
- return "Echoes everything"
21
-
22
- async def run(self, input: Message, *, context: Context) -> AsyncGenerator[Message | Await, AwaitResume]:
23
- for part in input:
24
- await asyncio.sleep(0.5)
25
- yield {"thought": "I should echo everyting"}
26
- yield Message(part)
27
-
28
-
29
- serve(EchoAgent())
@@ -1,3 +0,0 @@
1
- from acp_sdk.server.agent import Agent as Agent
2
- from acp_sdk.server.server import create_app as create_app
3
- from acp_sdk.server.server import serve as serve
@@ -1,35 +0,0 @@
1
- import abc
2
- from collections.abc import AsyncGenerator
3
-
4
- from acp_sdk.models import (
5
- AgentName,
6
- Await,
7
- AwaitResume,
8
- Message,
9
- SessionId,
10
- )
11
- from acp_sdk.models.models import Metadata
12
- from acp_sdk.server.context import Context
13
-
14
-
15
- class Agent(abc.ABC):
16
- @property
17
- def name(self) -> AgentName:
18
- return self.__class__.__name__
19
-
20
- @property
21
- def description(self) -> str:
22
- return ""
23
-
24
- @property
25
- def metadata(self) -> Metadata:
26
- return Metadata()
27
-
28
- @abc.abstractmethod
29
- def run(self, input: Message, *, context: Context) -> AsyncGenerator[Message | Await, AwaitResume]:
30
- pass
31
-
32
- async def session(self, session_id: SessionId | None) -> SessionId | None:
33
- if session_id:
34
- raise NotImplementedError()
35
- return None
@@ -1,6 +0,0 @@
1
- from acp_sdk.models import SessionId
2
-
3
-
4
- class Context:
5
- def __init__(self, *, session_id: SessionId | None = None) -> None:
6
- self.session_id = session_id
File without changes
File without changes