acp-sdk 0.7.0__tar.gz → 0.7.1__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 (48) hide show
  1. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/PKG-INFO +4 -4
  2. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/README.md +3 -3
  3. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/docs/client.md +4 -4
  4. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/docs/server.md +4 -4
  5. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/pyproject.toml +1 -1
  6. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/client/client.py +5 -28
  7. acp_sdk-0.7.1/src/acp_sdk/client/types.py +3 -0
  8. acp_sdk-0.7.1/src/acp_sdk/client/utils.py +24 -0
  9. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/agent.py +14 -14
  10. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/app.py +1 -1
  11. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/bundle.py +5 -5
  12. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/session.py +1 -1
  13. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/fixtures/server.py +8 -8
  14. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/test_suites/test_runs.py +23 -23
  15. acp_sdk-0.7.1/tests/unit/client/test_utils.py +30 -0
  16. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/.gitignore +0 -0
  17. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/.python-version +0 -0
  18. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/docs/_sidebar.md +0 -0
  19. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/docs/index.html +0 -0
  20. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/docs/models.md +0 -0
  21. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/pytest.ini +0 -0
  22. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/__init__.py +0 -0
  23. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/client/__init__.py +0 -0
  24. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/instrumentation.py +0 -0
  25. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/models/__init__.py +0 -0
  26. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/models/errors.py +0 -0
  27. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/models/models.py +0 -0
  28. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/models/schemas.py +0 -0
  29. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/py.typed +0 -0
  30. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/__init__.py +0 -0
  31. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/context.py +0 -0
  32. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/errors.py +0 -0
  33. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/logging.py +0 -0
  34. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/server.py +0 -0
  35. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/telemetry.py +0 -0
  36. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/types.py +0 -0
  37. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/server/utils.py +0 -0
  38. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/src/acp_sdk/version.py +0 -0
  39. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/conftest.py +0 -0
  40. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/__init__.py +0 -0
  41. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/config.py +0 -0
  42. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/fixtures/__init__.py +0 -0
  43. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/fixtures/client.py +0 -0
  44. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/test_suites/__init__.py +0 -0
  45. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/e2e/test_suites/test_discovery.py +0 -0
  46. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/unit/client/test_client.py +0 -0
  47. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/unit/models/__init__.py +0 -0
  48. {acp_sdk-0.7.0 → acp_sdk-0.7.1}/tests/unit/models/test_models.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: acp-sdk
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Agent Communication Protocol SDK
5
5
  Author: IBM Corp.
6
6
  Maintainer-email: Tomas Pilar <thomas7pilar@gmail.com>
@@ -44,9 +44,9 @@ Register an agent and run the server:
44
44
  server = Server()
45
45
 
46
46
  @server.agent()
47
- async def echo(inputs: list[Message]):
47
+ async def echo(input: list[Message]):
48
48
  """Echoes everything"""
49
- for message in inputs:
49
+ for message in input:
50
50
  yield message
51
51
 
52
52
  server.run(port=8000)
@@ -56,7 +56,7 @@ From another process, connect to the server and run the agent:
56
56
 
57
57
  ```py
58
58
  async with Client(base_url="http://localhost:8000") as client:
59
- run = await client.run_sync(agent="echo", inputs=[Message(parts=[MessagePart(content="Howdy!")])])
59
+ run = await client.run_sync(agent="echo", input=[Message(parts=[MessagePart(content="Howdy!")])])
60
60
  print(run)
61
61
 
62
62
  ```
@@ -23,9 +23,9 @@ Register an agent and run the server:
23
23
  server = Server()
24
24
 
25
25
  @server.agent()
26
- async def echo(inputs: list[Message]):
26
+ async def echo(input: list[Message]):
27
27
  """Echoes everything"""
28
- for message in inputs:
28
+ for message in input:
29
29
  yield message
30
30
 
31
31
  server.run(port=8000)
@@ -35,7 +35,7 @@ From another process, connect to the server and run the agent:
35
35
 
36
36
  ```py
37
37
  async with Client(base_url="http://localhost:8000") as client:
38
- run = await client.run_sync(agent="echo", inputs=[Message(parts=[MessagePart(content="Howdy!")])])
38
+ run = await client.run_sync(agent="echo", input=[Message(parts=[MessagePart(content="Howdy!")])])
39
39
  print(run)
40
40
 
41
41
  ```
@@ -71,15 +71,15 @@ async with Client(base_url="http://localhost:8000") as client:
71
71
  message = Message(parts=[MessagePart(content="Hello")])
72
72
 
73
73
  # Async
74
- run = await client.run_async(agent_name="agent", inputs=[message])
74
+ run = await client.run_async(agent_name="agent", input=[message])
75
75
  print(run.status)
76
76
 
77
77
  # Sync - waits for completion, failure, cancellation or await
78
- run = await client.run_sync(agent_name="agent", inputs=[message])
78
+ run = await client.run_sync(agent_name="agent", input=[message])
79
79
  print(run.output)
80
80
 
81
81
  # Stream - as sync but also receives events
82
- async for event in client.run_stream(agent_name="agent", inputs=[message])
82
+ async for event in client.run_stream(agent_name="agent", input=[message])
83
83
  print(event)
84
84
  ```
85
85
 
@@ -95,5 +95,5 @@ async with Client(base_url="http://localhost:8000" as client:
95
95
 
96
96
  async with client.session() as session:
97
97
  for agent in agents:
98
- await session.run_sync(agent_name=agent.name, inputs=[Message(parts=[MessagePart(content="Hello!")])])
98
+ await session.run_sync(agent_name=agent.name, input=[Message(parts=[MessagePart(content="Hello!")])])
99
99
  ```
@@ -47,9 +47,9 @@ server = Server()
47
47
 
48
48
 
49
49
  @server.agent()
50
- async def echo(inputs: list[Message], context: Context) -> AsyncGenerator[RunYield, RunYieldResume]:
50
+ async def echo(input: list[Message], context: Context) -> AsyncGenerator[RunYield, RunYieldResume]:
51
51
  """Echoes everything"""
52
- for message in inputs:
52
+ for message in input:
53
53
  await asyncio.sleep(0.5)
54
54
  yield {"thought": "I should echo everything"}
55
55
  await asyncio.sleep(0.5)
@@ -81,9 +81,9 @@ from acp_sdk.server import RunYield, RunYieldResume, agent, create_app
81
81
 
82
82
 
83
83
  @agent()
84
- async def echo(inputs: list[Message]) -> AsyncGenerator[RunYield, RunYieldResume]:
84
+ async def echo(input: list[Message]) -> AsyncGenerator[RunYield, RunYieldResume]:
85
85
  """Echoes everything"""
86
- for message in inputs:
86
+ for message in input:
87
87
  yield message
88
88
 
89
89
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "acp-sdk"
3
- version = "0.7.0"
3
+ version = "0.7.1"
4
4
  description = "Agent Communication Protocol SDK"
5
5
  license = "Apache-2.0"
6
6
  readme = "README.md"
@@ -11,6 +11,8 @@ from httpx_sse import EventSource, aconnect_sse
11
11
  from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
12
12
  from pydantic import TypeAdapter
13
13
 
14
+ from acp_sdk.client.types import Input
15
+ from acp_sdk.client.utils import input_to_messages
14
16
  from acp_sdk.instrumentation import get_tracer
15
17
  from acp_sdk.models import (
16
18
  ACPError,
@@ -21,7 +23,6 @@ from acp_sdk.models import (
21
23
  AwaitResume,
22
24
  Error,
23
25
  Event,
24
- Message,
25
26
  Run,
26
27
  RunCancelResponse,
27
28
  RunCreatedEvent,
@@ -33,9 +34,6 @@ from acp_sdk.models import (
33
34
  RunResumeResponse,
34
35
  SessionId,
35
36
  )
36
- from acp_sdk.models.models import MessagePart
37
-
38
- Input = list[Message] | Message | list[MessagePart] | MessagePart | list[str] | str
39
37
 
40
38
 
41
39
  class Client:
@@ -127,7 +125,7 @@ class Client:
127
125
  "/runs",
128
126
  content=RunCreateRequest(
129
127
  agent_name=agent,
130
- input=self._unify_inputs(input),
128
+ input=input_to_messages(input),
131
129
  mode=RunMode.SYNC,
132
130
  session_id=self._session_id,
133
131
  ).model_dump_json(),
@@ -142,7 +140,7 @@ class Client:
142
140
  "/runs",
143
141
  content=RunCreateRequest(
144
142
  agent_name=agent,
145
- input=self._unify_inputs(input),
143
+ input=input_to_messages(input),
146
144
  mode=RunMode.ASYNC,
147
145
  session_id=self._session_id,
148
146
  ).model_dump_json(),
@@ -159,7 +157,7 @@ class Client:
159
157
  "/runs",
160
158
  content=RunCreateRequest(
161
159
  agent_name=agent,
162
- input=self._unify_inputs(input),
160
+ input=input_to_messages(input),
163
161
  mode=RunMode.STREAM,
164
162
  session_id=self._session_id,
165
163
  ).model_dump_json(),
@@ -227,24 +225,3 @@ class Client:
227
225
 
228
226
  def _set_session(self, run: Run) -> None:
229
227
  self._session_id = run.session_id
230
-
231
- def _unify_inputs(self, input: Input) -> list[Message]:
232
- if isinstance(input, list):
233
- if len(input) == 0:
234
- return []
235
- if all(isinstance(item, Message) for item in input):
236
- return input
237
- elif all(isinstance(item, MessagePart) for item in input):
238
- return [Message(parts=input)]
239
- elif all(isinstance(item, str) for item in input):
240
- return [Message(parts=[MessagePart(content=content) for content in input])]
241
- else:
242
- raise RuntimeError("List with mixed types is not supported")
243
- else:
244
- if isinstance(input, str):
245
- input = MessagePart(content=input)
246
- if isinstance(input, MessagePart):
247
- input = Message(parts=[input])
248
- if isinstance(input, Message):
249
- input = [input]
250
- return input
@@ -0,0 +1,3 @@
1
+ from acp_sdk.models import Message, MessagePart
2
+
3
+ Input = list[Message] | Message | list[MessagePart] | MessagePart | list[str] | str
@@ -0,0 +1,24 @@
1
+ from acp_sdk.client.types import Input
2
+ from acp_sdk.models.models import Message, MessagePart
3
+
4
+
5
+ def input_to_messages(input: Input) -> list[Message]:
6
+ if isinstance(input, list):
7
+ if len(input) == 0:
8
+ return []
9
+ if all(isinstance(item, Message) for item in input):
10
+ return input
11
+ elif all(isinstance(item, MessagePart) for item in input):
12
+ return [Message(parts=input)]
13
+ elif all(isinstance(item, str) for item in input):
14
+ return [Message(parts=[MessagePart(content=content) for content in input])]
15
+ else:
16
+ raise TypeError("List with mixed types is not supported")
17
+ else:
18
+ if isinstance(input, str):
19
+ input = MessagePart(content=input)
20
+ if isinstance(input, MessagePart):
21
+ input = Message(parts=[input])
22
+ if isinstance(input, Message):
23
+ input = [input]
24
+ return input
@@ -32,14 +32,14 @@ class Agent(abc.ABC):
32
32
 
33
33
  @abc.abstractmethod
34
34
  def run(
35
- self, inputs: list[Message], context: Context
35
+ self, input: list[Message], context: Context
36
36
  ) -> (
37
37
  AsyncGenerator[RunYield, RunYieldResume] | Generator[RunYield, RunYieldResume] | Coroutine[RunYield] | RunYield
38
38
  ):
39
39
  pass
40
40
 
41
41
  async def execute(
42
- self, inputs: list[Message], session_id: SessionId | None, executor: ThreadPoolExecutor
42
+ self, input: list[Message], session_id: SessionId | None, executor: ThreadPoolExecutor
43
43
  ) -> AsyncGenerator[RunYield, RunYieldResume]:
44
44
  yield_queue: janus.Queue[RunYield] = janus.Queue()
45
45
  yield_resume_queue: janus.Queue[RunYieldResume] = janus.Queue()
@@ -49,13 +49,13 @@ class Agent(abc.ABC):
49
49
  )
50
50
 
51
51
  if inspect.isasyncgenfunction(self.run):
52
- run = asyncio.create_task(self._run_async_gen(inputs, context))
52
+ run = asyncio.create_task(self._run_async_gen(input, context))
53
53
  elif inspect.iscoroutinefunction(self.run):
54
- run = asyncio.create_task(self._run_coro(inputs, context))
54
+ run = asyncio.create_task(self._run_coro(input, context))
55
55
  elif inspect.isgeneratorfunction(self.run):
56
- run = asyncio.get_running_loop().run_in_executor(executor, self._run_gen, inputs, context)
56
+ run = asyncio.get_running_loop().run_in_executor(executor, self._run_gen, input, context)
57
57
  else:
58
- run = asyncio.get_running_loop().run_in_executor(executor, self._run_func, inputs, context)
58
+ run = asyncio.get_running_loop().run_in_executor(executor, self._run_func, input, context)
59
59
 
60
60
  try:
61
61
  while True:
@@ -66,7 +66,7 @@ class Agent(abc.ABC):
66
66
  finally:
67
67
  await run # Raise exceptions
68
68
 
69
- async def _run_async_gen(self, input: Message, context: Context) -> None:
69
+ async def _run_async_gen(self, input: list[Message], context: Context) -> None:
70
70
  try:
71
71
  gen: AsyncGenerator[RunYield, RunYieldResume] = self.run(input, context)
72
72
  value = None
@@ -77,13 +77,13 @@ class Agent(abc.ABC):
77
77
  finally:
78
78
  context.shutdown()
79
79
 
80
- async def _run_coro(self, input: Message, context: Context) -> None:
80
+ async def _run_coro(self, input: list[Message], context: Context) -> None:
81
81
  try:
82
82
  await context.yield_async(await self.run(input, context))
83
83
  finally:
84
84
  context.shutdown()
85
85
 
86
- def _run_gen(self, input: Message, context: Context) -> None:
86
+ def _run_gen(self, input: list[Message], context: Context) -> None:
87
87
  try:
88
88
  gen: Generator[RunYield, RunYieldResume] = self.run(input, context)
89
89
  value = None
@@ -94,7 +94,7 @@ class Agent(abc.ABC):
94
94
  finally:
95
95
  context.shutdown()
96
96
 
97
- def _run_func(self, input: Message, context: Context) -> None:
97
+ def _run_func(self, input: list[Message], context: Context) -> None:
98
98
  try:
99
99
  context.yield_sync(self.run(input, context))
100
100
  finally:
@@ -139,7 +139,7 @@ def agent(
139
139
  if inspect.isasyncgenfunction(fn):
140
140
 
141
141
  class AsyncGenDecoratorAgent(DecoratorAgentBase):
142
- async def run(self, input: Message, context: Context) -> AsyncGenerator[RunYield, RunYieldResume]:
142
+ async def run(self, input: list[Message], context: Context) -> AsyncGenerator[RunYield, RunYieldResume]:
143
143
  try:
144
144
  gen: AsyncGenerator[RunYield, RunYieldResume] = (
145
145
  fn(input, context) if has_context_param else fn(input)
@@ -154,21 +154,21 @@ def agent(
154
154
  elif inspect.iscoroutinefunction(fn):
155
155
 
156
156
  class CoroDecoratorAgent(DecoratorAgentBase):
157
- async def run(self, input: Message, context: Context) -> Coroutine[RunYield]:
157
+ async def run(self, input: list[Message], context: Context) -> Coroutine[RunYield]:
158
158
  return await (fn(input, context) if has_context_param else fn(input))
159
159
 
160
160
  agent = CoroDecoratorAgent()
161
161
  elif inspect.isgeneratorfunction(fn):
162
162
 
163
163
  class GenDecoratorAgent(DecoratorAgentBase):
164
- def run(self, input: Message, context: Context) -> Generator[RunYield, RunYieldResume]:
164
+ def run(self, input: list[Message], context: Context) -> Generator[RunYield, RunYieldResume]:
165
165
  yield from (fn(input, context) if has_context_param else fn(input))
166
166
 
167
167
  agent = GenDecoratorAgent()
168
168
  else:
169
169
 
170
170
  class FuncDecoratorAgent(DecoratorAgentBase):
171
- def run(self, input: Message, context: Context) -> RunYield:
171
+ def run(self, input: list[Message], context: Context) -> RunYield:
172
172
  return fn(input, context) if has_context_param else fn(input)
173
173
 
174
174
  agent = FuncDecoratorAgent()
@@ -105,7 +105,7 @@ def create_app(*agents: Agent, run_limit: int = 1000, run_ttl: timedelta = timed
105
105
  bundle = RunBundle(
106
106
  agent=agent,
107
107
  run=Run(agent_name=agent.name, session_id=session.id),
108
- inputs=request.input,
108
+ input=request.input,
109
109
  history=list(session.history()),
110
110
  executor=executor,
111
111
  )
@@ -35,11 +35,11 @@ from acp_sdk.server.logging import logger
35
35
 
36
36
  class RunBundle:
37
37
  def __init__(
38
- self, *, agent: Agent, run: Run, inputs: list[Message], history: list[Message], executor: ThreadPoolExecutor
38
+ self, *, agent: Agent, run: Run, input: list[Message], history: list[Message], executor: ThreadPoolExecutor
39
39
  ) -> None:
40
40
  self.agent = agent
41
41
  self.run = run
42
- self.inputs = inputs
42
+ self.input = input
43
43
  self.history = history
44
44
 
45
45
  self.stream_queue: asyncio.Queue[Event] = asyncio.Queue()
@@ -47,7 +47,7 @@ class RunBundle:
47
47
  self.await_queue: asyncio.Queue[AwaitResume] = asyncio.Queue(maxsize=1)
48
48
  self.await_or_terminate_event = asyncio.Event()
49
49
 
50
- self.task = asyncio.create_task(self._execute(inputs, executor=executor))
50
+ self.task = asyncio.create_task(self._execute(input, executor=executor))
51
51
 
52
52
  async def stream(self) -> AsyncGenerator[Event]:
53
53
  while True:
@@ -83,7 +83,7 @@ class RunBundle:
83
83
  async def join(self) -> None:
84
84
  await self.await_or_terminate_event.wait()
85
85
 
86
- async def _execute(self, inputs: list[Message], *, executor: ThreadPoolExecutor) -> None:
86
+ async def _execute(self, input: list[Message], *, executor: ThreadPoolExecutor) -> None:
87
87
  with get_tracer().start_as_current_span("run"):
88
88
  run_logger = logging.LoggerAdapter(logger, {"run_id": str(self.run.run_id)})
89
89
 
@@ -99,7 +99,7 @@ class RunBundle:
99
99
  await self.emit(RunCreatedEvent(run=self.run))
100
100
 
101
101
  generator = self.agent.execute(
102
- inputs=self.history + inputs, session_id=self.run.session_id, executor=executor
102
+ input=self.history + input, session_id=self.run.session_id, executor=executor
103
103
  )
104
104
  run_logger.info("Run started")
105
105
 
@@ -17,5 +17,5 @@ class Session:
17
17
  def history(self) -> Iterator[Message]:
18
18
  for bundle in self.bundles:
19
19
  if bundle.run.status == RunStatus.COMPLETED:
20
- yield from bundle.inputs
20
+ yield from bundle.input
21
21
  yield from bundle.run.output
@@ -17,36 +17,36 @@ def server(request: pytest.FixtureRequest) -> Generator[None]:
17
17
  server = Server()
18
18
 
19
19
  @server.agent()
20
- async def echo(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
21
- for message in inputs:
20
+ async def echo(input: list[Message], context: Context) -> AsyncIterator[Message]:
21
+ for message in input:
22
22
  yield message
23
23
 
24
24
  @server.agent()
25
25
  async def awaiter(
26
- inputs: list[Message], context: Context
26
+ input: list[Message], context: Context
27
27
  ) -> AsyncGenerator[Message | MessageAwaitRequest, AwaitResume]:
28
28
  yield MessageAwaitRequest(message=Message(parts=[]))
29
29
  yield MessagePart(content="empty", content_type="text/plain")
30
30
 
31
31
  @server.agent()
32
- async def failer(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
32
+ async def failer(input: list[Message], context: Context) -> AsyncIterator[Message]:
33
33
  yield Error(code=ErrorCode.INVALID_INPUT, message="Wrong question buddy!")
34
34
 
35
35
  @server.agent()
36
- async def sessioner(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
36
+ async def sessioner(input: list[Message], context: Context) -> AsyncIterator[Message]:
37
37
  assert context.session_id is not None
38
38
 
39
39
  yield MessagePart(content=str(context.session_id), content_type="text/plain")
40
40
 
41
41
  @server.agent()
42
- async def mime_types(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
42
+ async def mime_types(input: list[Message], context: Context) -> AsyncIterator[Message]:
43
43
  yield MessagePart(content="<h1>HTML Content</h1>", content_type="text/html")
44
44
  yield MessagePart(content='{"key": "value"}', content_type="application/json")
45
45
  yield MessagePart(content="console.log('Hello');", content_type="application/javascript")
46
46
  yield MessagePart(content="body { color: red; }", content_type="text/css")
47
47
 
48
48
  @server.agent()
49
- async def base64_encoding(inputs: list[Message], context: Context) -> AsyncIterator[Message]:
49
+ async def base64_encoding(input: list[Message], context: Context) -> AsyncIterator[Message]:
50
50
  yield Message(
51
51
  parts=[
52
52
  MessagePart(
@@ -61,7 +61,7 @@ def server(request: pytest.FixtureRequest) -> Generator[None]:
61
61
  )
62
62
 
63
63
  @server.agent()
64
- async def artifact_producer(inputs: list[Message], context: Context) -> AsyncGenerator[Message | Artifact, None]:
64
+ async def artifact_producer(input: list[Message], context: Context) -> AsyncGenerator[Message | Artifact, None]:
65
65
  yield MessagePart(content="Processing with artifacts", content_type="text/plain")
66
66
  yield Artifact(name="text-result.txt", content_type="text/plain", content="This is a text artifact result")
67
67
  yield Artifact(
@@ -19,33 +19,33 @@ from acp_sdk.models import (
19
19
  from acp_sdk.models.errors import ACPError
20
20
  from acp_sdk.server import Server
21
21
 
22
- inputs = [Message(parts=[MessagePart(content="Hello!")])]
22
+ input = [Message(parts=[MessagePart(content="Hello!")])]
23
23
  await_resume = MessageAwaitResume(message=Message(parts=[]))
24
24
 
25
25
 
26
26
  @pytest.mark.asyncio
27
27
  async def test_run_sync(server: Server, client: Client) -> None:
28
- run = await client.run_sync(agent="echo", input=inputs)
28
+ run = await client.run_sync(agent="echo", input=input)
29
29
  assert run.status == RunStatus.COMPLETED
30
- assert run.output == inputs
30
+ assert run.output == input
31
31
 
32
32
 
33
33
  @pytest.mark.asyncio
34
34
  async def test_run_async(server: Server, client: Client) -> None:
35
- run = await client.run_async(agent="echo", input=inputs)
35
+ run = await client.run_async(agent="echo", input=input)
36
36
  assert run.status == RunStatus.CREATED
37
37
 
38
38
 
39
39
  @pytest.mark.asyncio
40
40
  async def test_run_stream(server: Server, client: Client) -> None:
41
- event_stream = [event async for event in client.run_stream(agent="echo", input=inputs)]
41
+ event_stream = [event async for event in client.run_stream(agent="echo", input=input)]
42
42
  assert isinstance(event_stream[0], RunCreatedEvent)
43
43
  assert isinstance(event_stream[-1], RunCompletedEvent)
44
44
 
45
45
 
46
46
  @pytest.mark.asyncio
47
47
  async def test_run_status(server: Server, client: Client) -> None:
48
- run = await client.run_async(agent="echo", input=inputs)
48
+ run = await client.run_async(agent="echo", input=input)
49
49
  while run.status in (RunStatus.CREATED, RunStatus.IN_PROGRESS):
50
50
  run = await client.run_status(run_id=run.run_id)
51
51
  assert run.status == RunStatus.COMPLETED
@@ -53,7 +53,7 @@ async def test_run_status(server: Server, client: Client) -> None:
53
53
 
54
54
  @pytest.mark.asyncio
55
55
  async def test_failure(server: Server, client: Client) -> None:
56
- run = await client.run_sync(agent="failer", input=inputs)
56
+ run = await client.run_sync(agent="failer", input=input)
57
57
  assert run.status == RunStatus.FAILED
58
58
  assert run.error is not None
59
59
  assert run.error.code == ErrorCode.INVALID_INPUT
@@ -61,7 +61,7 @@ async def test_failure(server: Server, client: Client) -> None:
61
61
 
62
62
  @pytest.mark.asyncio
63
63
  async def test_run_cancel(server: Server, client: Client) -> None:
64
- run = await client.run_sync(agent="awaiter", input=inputs)
64
+ run = await client.run_sync(agent="awaiter", input=input)
65
65
  assert run.status == RunStatus.AWAITING
66
66
  run = await client.run_cancel(run_id=run.run_id)
67
67
  assert run.status == RunStatus.CANCELLING
@@ -69,7 +69,7 @@ async def test_run_cancel(server: Server, client: Client) -> None:
69
69
 
70
70
  @pytest.mark.asyncio
71
71
  async def test_run_resume_sync(server: Server, client: Client) -> None:
72
- run = await client.run_sync(agent="awaiter", input=inputs)
72
+ run = await client.run_sync(agent="awaiter", input=input)
73
73
  assert run.status == RunStatus.AWAITING
74
74
  assert run.await_request is not None
75
75
 
@@ -79,7 +79,7 @@ async def test_run_resume_sync(server: Server, client: Client) -> None:
79
79
 
80
80
  @pytest.mark.asyncio
81
81
  async def test_run_resume_async(server: Server, client: Client) -> None:
82
- run = await client.run_sync(agent="awaiter", input=inputs)
82
+ run = await client.run_sync(agent="awaiter", input=input)
83
83
  assert run.status == RunStatus.AWAITING
84
84
  assert run.await_request is not None
85
85
 
@@ -89,7 +89,7 @@ async def test_run_resume_async(server: Server, client: Client) -> None:
89
89
 
90
90
  @pytest.mark.asyncio
91
91
  async def test_run_resume_stream(server: Server, client: Client) -> None:
92
- run = await client.run_sync(agent="awaiter", input=inputs)
92
+ run = await client.run_sync(agent="awaiter", input=input)
93
93
  assert run.status == RunStatus.AWAITING
94
94
  assert run.await_request is not None
95
95
 
@@ -101,15 +101,15 @@ async def test_run_resume_stream(server: Server, client: Client) -> None:
101
101
  @pytest.mark.asyncio
102
102
  async def test_run_session(server: Server, client: Client) -> None:
103
103
  async with client.session() as session:
104
- run = await session.run_sync(agent="echo", input=inputs)
105
- assert run.output == inputs
106
- run = await session.run_sync(agent="echo", input=inputs)
107
- assert run.output == inputs + inputs + inputs
104
+ run = await session.run_sync(agent="echo", input=input)
105
+ assert run.output == input
106
+ run = await session.run_sync(agent="echo", input=input)
107
+ assert run.output == input + input + input
108
108
 
109
109
 
110
110
  @pytest.mark.asyncio
111
111
  async def test_mime_types(server: Server, client: Client) -> None:
112
- run = await client.run_sync(agent="mime_types", input=inputs)
112
+ run = await client.run_sync(agent="mime_types", input=input)
113
113
  assert run.status == RunStatus.COMPLETED
114
114
  assert len(run.output) == 1
115
115
 
@@ -130,7 +130,7 @@ async def test_mime_types(server: Server, client: Client) -> None:
130
130
 
131
131
  @pytest.mark.asyncio
132
132
  async def test_base64_encoding(server: Server, client: Client) -> None:
133
- run = await client.run_sync(agent="base64_encoding", input=inputs)
133
+ run = await client.run_sync(agent="base64_encoding", input=input)
134
134
  assert run.status == RunStatus.COMPLETED
135
135
  assert len(run.output) == 1
136
136
 
@@ -150,7 +150,7 @@ async def test_base64_encoding(server: Server, client: Client) -> None:
150
150
 
151
151
  @pytest.mark.asyncio
152
152
  async def test_artifacts(server: Server, client: Client) -> None:
153
- run = await client.run_sync(agent="artifact_producer", input=inputs)
153
+ run = await client.run_sync(agent="artifact_producer", input=input)
154
154
  assert run.status == RunStatus.COMPLETED
155
155
 
156
156
  assert len(run.output) == 1
@@ -179,7 +179,7 @@ async def test_artifacts(server: Server, client: Client) -> None:
179
179
 
180
180
  @pytest.mark.asyncio
181
181
  async def test_artifact_streaming(server: Server, client: Client) -> None:
182
- events = [event async for event in client.run_stream(agent="artifact_producer", input=inputs)]
182
+ events = [event async for event in client.run_stream(agent="artifact_producer", input=input)]
183
183
 
184
184
  assert isinstance(events[0], RunCreatedEvent)
185
185
  assert isinstance(events[-1], RunCompletedEvent)
@@ -201,7 +201,7 @@ async def test_artifact_streaming(server: Server, client: Client) -> None:
201
201
  @pytest.mark.asyncio
202
202
  @pytest.mark.parametrize("server", [timedelta(seconds=5)], indirect=True)
203
203
  async def test_run_ttl(server: Server, client: Client) -> None:
204
- run = await client.run_async(agent="echo", input=inputs)
204
+ run = await client.run_async(agent="echo", input=input)
205
205
  run = await client.run_status(run_id=run.run_id)
206
206
  await asyncio.sleep(6)
207
207
  try:
@@ -218,10 +218,10 @@ async def test_run_ttl(server: Server, client: Client) -> None:
218
218
  @pytest.mark.parametrize("server", [timedelta(seconds=5)], indirect=True)
219
219
  async def test_session_ttl(server: Server, client: Client) -> None:
220
220
  async with client.session() as session:
221
- run = await session.run_sync(agent="echo", input=inputs)
221
+ run = await session.run_sync(agent="echo", input=input)
222
222
  await asyncio.sleep(3)
223
- run = await session.run_sync(agent="echo", input=inputs)
223
+ run = await session.run_sync(agent="echo", input=input)
224
224
  assert len(run.output) == 3
225
225
  await asyncio.sleep(3)
226
- run = await session.run_sync(agent="echo", input=inputs)
226
+ run = await session.run_sync(agent="echo", input=input)
227
227
  assert len(run.output) == 7 # First run shall be forgotten
@@ -0,0 +1,30 @@
1
+ import pytest
2
+ from acp_sdk.client.types import Input
3
+ from acp_sdk.client.utils import input_to_messages
4
+ from acp_sdk.models import Message, MessagePart
5
+
6
+
7
+ @pytest.mark.parametrize(
8
+ "input,messages",
9
+ [
10
+ ([], []),
11
+ ("Hello", [Message(parts=[MessagePart(content="Hello")])]),
12
+ (["Hello"], [Message(parts=[MessagePart(content="Hello")])]),
13
+ (MessagePart(content="Hello"), [Message(parts=[MessagePart(content="Hello")])]),
14
+ ([MessagePart(content="Hello")], [Message(parts=[MessagePart(content="Hello")])]),
15
+ (Message(parts=[MessagePart(content="Hello")]), [Message(parts=[MessagePart(content="Hello")])]),
16
+ ([Message(parts=[MessagePart(content="Hello")])], [Message(parts=[MessagePart(content="Hello")])]),
17
+ ],
18
+ )
19
+ def test_input_to_messages(input: Input, messages: list[Message]) -> None:
20
+ result = input_to_messages(input)
21
+ assert result == messages
22
+
23
+
24
+ @pytest.mark.parametrize(
25
+ "input",
26
+ [["foo", Message(parts=[])], ["foo", MessagePart(content="foo")], [Message(parts=[]), MessagePart(content="foo")]],
27
+ )
28
+ def test_input_to_messages_mixed_input(input: Input) -> None:
29
+ with pytest.raises(TypeError):
30
+ input_to_messages(["foo", Message(parts=[])])
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