acp-sdk 0.7.2__tar.gz → 0.8.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.7.2 → acp_sdk-0.8.0}/PKG-INFO +1 -1
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/pyproject.toml +1 -1
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/client/client.py +12 -10
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/models/models.py +11 -3
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/models/schemas.py +9 -1
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/app.py +11 -4
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/bundle.py +12 -3
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/session.py +2 -2
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/test_suites/test_discovery.py +6 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/test_suites/test_runs.py +22 -4
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/unit/client/test_client.py +38 -2
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/unit/client/test_utils.py +2 -1
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/unit/models/test_models.py +29 -7
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/.gitignore +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/.python-version +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/README.md +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/docs/_sidebar.md +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/docs/client.md +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/docs/index.html +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/docs/models.md +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/docs/server.md +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/pytest.ini +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/client/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/client/types.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/client/utils.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/instrumentation.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/models/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/models/errors.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/py.typed +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/agent.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/context.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/errors.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/logging.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/server.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/telemetry.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/types.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/server/utils.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/src/acp_sdk/version.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/conftest.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/config.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/fixtures/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/fixtures/client.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/fixtures/server.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/e2e/test_suites/__init__.py +0 -0
- {acp_sdk-0.7.2 → acp_sdk-0.8.0}/tests/unit/models/__init__.py +0 -0
@@ -23,11 +23,12 @@ from acp_sdk.models import (
|
|
23
23
|
AwaitResume,
|
24
24
|
Error,
|
25
25
|
Event,
|
26
|
+
PingResponse,
|
26
27
|
Run,
|
27
28
|
RunCancelResponse,
|
28
|
-
RunCreatedEvent,
|
29
29
|
RunCreateRequest,
|
30
30
|
RunCreateResponse,
|
31
|
+
RunEventsListResponse,
|
31
32
|
RunId,
|
32
33
|
RunMode,
|
33
34
|
RunResumeRequest,
|
@@ -121,9 +122,10 @@ class Client:
|
|
121
122
|
return Agent(**response.model_dump())
|
122
123
|
|
123
124
|
async def ping(self) -> bool:
|
124
|
-
response = await self._client.get("/
|
125
|
+
response = await self._client.get("/ping")
|
125
126
|
self._raise_error(response)
|
126
|
-
|
127
|
+
PingResponse.model_validate(response.json())
|
128
|
+
return
|
127
129
|
|
128
130
|
async def run_sync(self, input: Input, *, agent: AgentName) -> Run:
|
129
131
|
response = await self._client.post(
|
@@ -137,7 +139,6 @@ class Client:
|
|
137
139
|
)
|
138
140
|
self._raise_error(response)
|
139
141
|
response = RunCreateResponse.model_validate(response.json())
|
140
|
-
self._set_session(response)
|
141
142
|
return Run(**response.model_dump())
|
142
143
|
|
143
144
|
async def run_async(self, input: Input, *, agent: AgentName) -> Run:
|
@@ -152,7 +153,6 @@ class Client:
|
|
152
153
|
)
|
153
154
|
self._raise_error(response)
|
154
155
|
response = RunCreateResponse.model_validate(response.json())
|
155
|
-
self._set_session(response)
|
156
156
|
return Run(**response.model_dump())
|
157
157
|
|
158
158
|
async def run_stream(self, input: Input, *, agent: AgentName) -> AsyncIterator[Event]:
|
@@ -168,8 +168,6 @@ class Client:
|
|
168
168
|
).model_dump_json(),
|
169
169
|
) as event_source:
|
170
170
|
async for event in self._validate_stream(event_source):
|
171
|
-
if isinstance(event, RunCreatedEvent):
|
172
|
-
self._set_session(event.run)
|
173
171
|
yield event
|
174
172
|
|
175
173
|
async def run_status(self, *, run_id: RunId) -> Run:
|
@@ -177,6 +175,13 @@ class Client:
|
|
177
175
|
self._raise_error(response)
|
178
176
|
return Run.model_validate(response.json())
|
179
177
|
|
178
|
+
async def run_events(self, *, run_id: RunId) -> AsyncIterator[Event]:
|
179
|
+
response = await self._client.get(f"/runs/{run_id}/events")
|
180
|
+
self._raise_error(response)
|
181
|
+
response = RunEventsListResponse.model_validate(response.json())
|
182
|
+
for event in response.events:
|
183
|
+
yield event
|
184
|
+
|
180
185
|
async def run_cancel(self, *, run_id: RunId) -> Run:
|
181
186
|
response = await self._client.post(f"/runs/{run_id}/cancel")
|
182
187
|
self._raise_error(response)
|
@@ -227,6 +232,3 @@ class Client:
|
|
227
232
|
response.raise_for_status()
|
228
233
|
except httpx.HTTPError:
|
229
234
|
raise ACPError(Error.model_validate(response.json()))
|
230
|
-
|
231
|
-
def _set_session(self, run: Run) -> None:
|
232
|
-
self._session_id = run.session_id
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import uuid
|
2
|
-
from datetime import datetime
|
2
|
+
from datetime import datetime, timezone
|
3
3
|
from enum import Enum
|
4
4
|
from typing import Any, Literal, Optional, Union
|
5
5
|
|
@@ -95,11 +95,17 @@ class Artifact(MessagePart):
|
|
95
95
|
|
96
96
|
class Message(BaseModel):
|
97
97
|
parts: list[MessagePart]
|
98
|
+
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
99
|
+
completed_at: datetime | None = Field(default_factory=lambda: datetime.now(timezone.utc))
|
98
100
|
|
99
101
|
def __add__(self, other: "Message") -> "Message":
|
100
102
|
if not isinstance(other, Message):
|
101
103
|
raise TypeError(f"Cannot concatenate Message with {type(other).__name__}")
|
102
|
-
return Message(
|
104
|
+
return Message(
|
105
|
+
parts=self.parts + other.parts,
|
106
|
+
created_at=min(self.created_at, other.created_at),
|
107
|
+
completed_at=max(self.completed_at, other.completed_at),
|
108
|
+
)
|
103
109
|
|
104
110
|
def __str__(self) -> str:
|
105
111
|
return "".join(
|
@@ -134,7 +140,7 @@ class Message(BaseModel):
|
|
134
140
|
parts[-1] = join(parts[-1], part)
|
135
141
|
else:
|
136
142
|
parts.append(part)
|
137
|
-
return Message(parts=parts)
|
143
|
+
return Message(parts=parts, created_at=self.created_at, completed_at=self.completed_at)
|
138
144
|
|
139
145
|
|
140
146
|
AgentName = str
|
@@ -185,6 +191,8 @@ class Run(BaseModel):
|
|
185
191
|
await_request: AwaitRequest | None = None
|
186
192
|
output: list[Message] = []
|
187
193
|
error: Error | None = None
|
194
|
+
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
|
195
|
+
finished_at: datetime | None = None
|
188
196
|
|
189
197
|
|
190
198
|
class MessageCreatedEvent(BaseModel):
|
@@ -1,6 +1,10 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
2
|
|
3
|
-
from acp_sdk.models.models import Agent, AgentName, AwaitResume, Message, Run, RunMode, SessionId
|
3
|
+
from acp_sdk.models.models import Agent, AgentName, AwaitResume, Event, Message, Run, RunMode, SessionId
|
4
|
+
|
5
|
+
|
6
|
+
class PingResponse(BaseModel):
|
7
|
+
pass
|
4
8
|
|
5
9
|
|
6
10
|
class AgentsListResponse(BaseModel):
|
@@ -37,3 +41,7 @@ class RunReadResponse(Run):
|
|
37
41
|
|
38
42
|
class RunCancelResponse(Run):
|
39
43
|
pass
|
44
|
+
|
45
|
+
|
46
|
+
class RunEventsListResponse(BaseModel):
|
47
|
+
events: list[Event]
|
@@ -21,6 +21,7 @@ from acp_sdk.models import (
|
|
21
21
|
RunCancelResponse,
|
22
22
|
RunCreateRequest,
|
23
23
|
RunCreateResponse,
|
24
|
+
RunEventsListResponse,
|
24
25
|
RunId,
|
25
26
|
RunMode,
|
26
27
|
RunReadResponse,
|
@@ -29,6 +30,7 @@ from acp_sdk.models import (
|
|
29
30
|
SessionId,
|
30
31
|
)
|
31
32
|
from acp_sdk.models.errors import ACPError
|
33
|
+
from acp_sdk.models.schemas import PingResponse
|
32
34
|
from acp_sdk.server.agent import Agent
|
33
35
|
from acp_sdk.server.bundle import RunBundle
|
34
36
|
from acp_sdk.server.errors import (
|
@@ -104,15 +106,15 @@ def create_app(
|
|
104
106
|
agent = find_agent(name)
|
105
107
|
return AgentModel(name=agent.name, description=agent.description, metadata=agent.metadata)
|
106
108
|
|
107
|
-
@app.get("/
|
108
|
-
async def
|
109
|
-
return
|
109
|
+
@app.get("/ping")
|
110
|
+
async def ping() -> PingResponse:
|
111
|
+
return PingResponse()
|
110
112
|
|
111
113
|
@app.post("/runs")
|
112
114
|
async def create_run(request: RunCreateRequest) -> RunCreateResponse:
|
113
115
|
agent = find_agent(request.agent_name)
|
114
116
|
|
115
|
-
session = sessions.get(request.session_id, Session()) if request.session_id else Session()
|
117
|
+
session = sessions.get(request.session_id, Session(id=request.session_id)) if request.session_id else Session()
|
116
118
|
nonlocal executor
|
117
119
|
bundle = RunBundle(
|
118
120
|
agent=agent,
|
@@ -155,6 +157,11 @@ def create_app(
|
|
155
157
|
bundle = find_run_bundle(run_id)
|
156
158
|
return bundle.run
|
157
159
|
|
160
|
+
@app.get("/runs/{run_id}/events")
|
161
|
+
async def list_run_events(run_id: RunId) -> RunEventsListResponse:
|
162
|
+
bundle = find_run_bundle(run_id)
|
163
|
+
return RunEventsListResponse(events=bundle.events)
|
164
|
+
|
158
165
|
@app.post("/runs/{run_id}")
|
159
166
|
async def resume_run(run_id: RunId, request: RunResumeRequest) -> RunResumeResponse:
|
160
167
|
bundle = find_run_bundle(run_id)
|
@@ -2,6 +2,7 @@ import asyncio
|
|
2
2
|
import logging
|
3
3
|
from collections.abc import AsyncGenerator
|
4
4
|
from concurrent.futures import ThreadPoolExecutor
|
5
|
+
from datetime import datetime, timezone
|
5
6
|
|
6
7
|
from pydantic import BaseModel, ValidationError
|
7
8
|
|
@@ -43,6 +44,7 @@ class RunBundle:
|
|
43
44
|
self.history = history
|
44
45
|
|
45
46
|
self.stream_queue: asyncio.Queue[Event] = asyncio.Queue()
|
47
|
+
self.events: list[Event] = []
|
46
48
|
|
47
49
|
self.await_queue: asyncio.Queue[AwaitResume] = asyncio.Queue(maxsize=1)
|
48
50
|
self.await_or_terminate_event = asyncio.Event()
|
@@ -58,7 +60,9 @@ class RunBundle:
|
|
58
60
|
self.stream_queue.task_done()
|
59
61
|
|
60
62
|
async def emit(self, event: Event) -> None:
|
61
|
-
|
63
|
+
freeze = event.model_copy(deep=True)
|
64
|
+
self.events.append(freeze)
|
65
|
+
await self.stream_queue.put(freeze)
|
62
66
|
|
63
67
|
async def await_(self) -> AwaitResume:
|
64
68
|
await self.stream_queue.put(None)
|
@@ -92,7 +96,9 @@ class RunBundle:
|
|
92
96
|
async def flush_message() -> None:
|
93
97
|
nonlocal in_message
|
94
98
|
if in_message:
|
95
|
-
|
99
|
+
message = self.run.output[-1]
|
100
|
+
message.completed_at = datetime.now(timezone.utc)
|
101
|
+
await self.emit(MessageCompletedEvent(message=message))
|
96
102
|
in_message = False
|
97
103
|
|
98
104
|
try:
|
@@ -114,7 +120,7 @@ class RunBundle:
|
|
114
120
|
if isinstance(next, str):
|
115
121
|
next = MessagePart(content=next)
|
116
122
|
if not in_message:
|
117
|
-
self.run.output.append(Message(parts=[]))
|
123
|
+
self.run.output.append(Message(parts=[], completed_at=None))
|
118
124
|
in_message = True
|
119
125
|
await self.emit(MessageCreatedEvent(message=self.run.output[-1]))
|
120
126
|
self.run.output[-1].parts.append(next)
|
@@ -149,10 +155,12 @@ class RunBundle:
|
|
149
155
|
except StopAsyncIteration:
|
150
156
|
await flush_message()
|
151
157
|
self.run.status = RunStatus.COMPLETED
|
158
|
+
self.run.finished_at = datetime.now(timezone.utc)
|
152
159
|
await self.emit(RunCompletedEvent(run=self.run))
|
153
160
|
run_logger.info("Run completed")
|
154
161
|
except asyncio.CancelledError:
|
155
162
|
self.run.status = RunStatus.CANCELLED
|
163
|
+
self.run.finished_at = datetime.now(timezone.utc)
|
156
164
|
await self.emit(RunCancelledEvent(run=self.run))
|
157
165
|
run_logger.info("Run cancelled")
|
158
166
|
except Exception as e:
|
@@ -161,6 +169,7 @@ class RunBundle:
|
|
161
169
|
else:
|
162
170
|
self.run.error = Error(code=ErrorCode.SERVER_ERROR, message=str(e))
|
163
171
|
self.run.status = RunStatus.FAILED
|
172
|
+
self.run.finished_at = datetime.now(timezone.utc)
|
164
173
|
await self.emit(RunFailedEvent(run=self.run))
|
165
174
|
run_logger.exception("Run failed")
|
166
175
|
raise
|
@@ -7,8 +7,8 @@ from acp_sdk.server.bundle import RunBundle
|
|
7
7
|
|
8
8
|
|
9
9
|
class Session:
|
10
|
-
def __init__(self) -> None:
|
11
|
-
self.id: SessionId = uuid.uuid4()
|
10
|
+
def __init__(self, id: SessionId | None = None) -> None:
|
11
|
+
self.id: SessionId = id or uuid.uuid4()
|
12
12
|
self.bundles: list[RunBundle] = []
|
13
13
|
|
14
14
|
def append(self, bundle: RunBundle) -> None:
|
@@ -4,6 +4,12 @@ from acp_sdk.models import Agent
|
|
4
4
|
from acp_sdk.server import Server
|
5
5
|
|
6
6
|
|
7
|
+
@pytest.mark.asyncio
|
8
|
+
async def test_ping(server: Server, client: Client) -> None:
|
9
|
+
await client.ping()
|
10
|
+
assert True
|
11
|
+
|
12
|
+
|
7
13
|
@pytest.mark.asyncio
|
8
14
|
async def test_agents_list(server: Server, client: Client) -> None:
|
9
15
|
async for agent in client.agents():
|
@@ -9,8 +9,8 @@ from acp_sdk.models import (
|
|
9
9
|
ErrorCode,
|
10
10
|
Message,
|
11
11
|
MessageAwaitResume,
|
12
|
-
MessageCreatedEvent,
|
13
12
|
MessagePart,
|
13
|
+
MessagePartEvent,
|
14
14
|
RunCompletedEvent,
|
15
15
|
RunCreatedEvent,
|
16
16
|
RunInProgressEvent,
|
@@ -51,6 +51,24 @@ async def test_run_status(server: Server, client: Client) -> None:
|
|
51
51
|
assert run.status == RunStatus.COMPLETED
|
52
52
|
|
53
53
|
|
54
|
+
@pytest.mark.asyncio
|
55
|
+
async def test_run_events(server: Server, client: Client) -> None:
|
56
|
+
run = await client.run_sync(agent="echo", input=input)
|
57
|
+
events = [event async for event in client.run_events(run_id=run.run_id)]
|
58
|
+
assert isinstance(events[0], RunCreatedEvent)
|
59
|
+
assert isinstance(events[-1], RunCompletedEvent)
|
60
|
+
|
61
|
+
|
62
|
+
@pytest.mark.asyncio
|
63
|
+
async def test_run_events_are_stream(server: Server, client: Client) -> None:
|
64
|
+
stream = [event async for event in client.run_stream(agent="echo", input=input)]
|
65
|
+
print(stream)
|
66
|
+
assert isinstance(stream[0], RunCreatedEvent)
|
67
|
+
events = [event async for event in client.run_events(run_id=stream[0].run.run_id)]
|
68
|
+
print(events)
|
69
|
+
assert stream == events
|
70
|
+
|
71
|
+
|
54
72
|
@pytest.mark.asyncio
|
55
73
|
async def test_failure(server: Server, client: Client) -> None:
|
56
74
|
run = await client.run_sync(agent="failer", input=input)
|
@@ -184,11 +202,11 @@ async def test_artifact_streaming(server: Server, client: Client) -> None:
|
|
184
202
|
assert isinstance(events[0], RunCreatedEvent)
|
185
203
|
assert isinstance(events[-1], RunCompletedEvent)
|
186
204
|
|
187
|
-
|
205
|
+
message_part_events = [e for e in events if isinstance(e, MessagePartEvent)]
|
188
206
|
artifact_events = [e for e in events if isinstance(e, ArtifactEvent)]
|
189
207
|
|
190
|
-
assert len(
|
191
|
-
assert
|
208
|
+
assert len(message_part_events) == 1
|
209
|
+
assert message_part_events[0].part.content == "Processing with artifacts"
|
192
210
|
|
193
211
|
assert len(artifact_events) == 3
|
194
212
|
|
@@ -3,8 +3,16 @@ import uuid
|
|
3
3
|
|
4
4
|
import pytest
|
5
5
|
from acp_sdk.client import Client
|
6
|
-
from acp_sdk.models import
|
7
|
-
|
6
|
+
from acp_sdk.models import (
|
7
|
+
Agent,
|
8
|
+
AgentsListResponse,
|
9
|
+
Message,
|
10
|
+
MessageAwaitResume,
|
11
|
+
MessagePart,
|
12
|
+
Run,
|
13
|
+
RunCompletedEvent,
|
14
|
+
RunEventsListResponse,
|
15
|
+
)
|
8
16
|
from pytest_httpx import HTTPXMock
|
9
17
|
|
10
18
|
mock_agent = Agent(name="mock")
|
@@ -128,6 +136,20 @@ async def test_run_resume_stream(httpx_mock: HTTPXMock) -> None:
|
|
128
136
|
assert event == mock_event
|
129
137
|
|
130
138
|
|
139
|
+
@pytest.mark.asyncio
|
140
|
+
async def test_run_events(httpx_mock: HTTPXMock) -> None:
|
141
|
+
mock_event = RunCompletedEvent(run=mock_run)
|
142
|
+
httpx_mock.add_response(
|
143
|
+
url=f"http://test/runs/{mock_run.run_id}/events",
|
144
|
+
method="GET",
|
145
|
+
content=RunEventsListResponse(events=[mock_event]).model_dump_json(),
|
146
|
+
)
|
147
|
+
|
148
|
+
async with Client(base_url="http://test") as client:
|
149
|
+
async for event in client.run_events(run_id=mock_run.run_id):
|
150
|
+
assert event == mock_event
|
151
|
+
|
152
|
+
|
131
153
|
@pytest.mark.asyncio
|
132
154
|
async def test_session(httpx_mock: HTTPXMock) -> None:
|
133
155
|
httpx_mock.add_response(url="http://test/runs", method="POST", content=mock_run.model_dump_json(), is_reusable=True)
|
@@ -143,3 +165,17 @@ async def test_session(httpx_mock: HTTPXMock) -> None:
|
|
143
165
|
|
144
166
|
body = json.loads(requests[1].content)
|
145
167
|
assert body["session_id"] is None
|
168
|
+
|
169
|
+
|
170
|
+
@pytest.mark.asyncio
|
171
|
+
async def test_no_session(httpx_mock: HTTPXMock) -> None:
|
172
|
+
httpx_mock.add_response(url="http://test/runs", method="POST", content=mock_run.model_dump_json(), is_reusable=True)
|
173
|
+
|
174
|
+
async with Client(base_url="http://test") as client:
|
175
|
+
await client.run_sync("Howdy!", agent=mock_run.agent_name)
|
176
|
+
await client.run_sync("Howdy!", agent=mock_run.agent_name)
|
177
|
+
|
178
|
+
requests = httpx_mock.get_requests()
|
179
|
+
|
180
|
+
body = json.loads(requests[1].content)
|
181
|
+
assert body["session_id"] is None
|
@@ -18,7 +18,8 @@ from acp_sdk.models import Message, MessagePart
|
|
18
18
|
)
|
19
19
|
def test_input_to_messages(input: Input, messages: list[Message]) -> None:
|
20
20
|
result = input_to_messages(input)
|
21
|
-
|
21
|
+
for r, m in zip(result, messages):
|
22
|
+
assert r.parts == m.parts
|
22
23
|
|
23
24
|
|
24
25
|
@pytest.mark.parametrize(
|
@@ -1,18 +1,30 @@
|
|
1
1
|
import pytest
|
2
2
|
from acp_sdk.models.models import Message, MessagePart
|
3
3
|
|
4
|
+
timestamp = "2021-09-09T22:02:47.89Z"
|
5
|
+
|
4
6
|
|
5
7
|
@pytest.mark.parametrize(
|
6
8
|
"first,second,result",
|
7
9
|
[
|
8
10
|
(
|
9
|
-
Message(
|
10
|
-
|
11
|
+
Message(
|
12
|
+
parts=[MessagePart(content_type="text/plain", content="Foo")],
|
13
|
+
created_at=timestamp,
|
14
|
+
completed_at=timestamp,
|
15
|
+
),
|
16
|
+
Message(
|
17
|
+
parts=[MessagePart(content_type="text/plain", content="Bar")],
|
18
|
+
created_at=timestamp,
|
19
|
+
completed_at=timestamp,
|
20
|
+
),
|
11
21
|
Message(
|
12
22
|
parts=[
|
13
23
|
MessagePart(content_type="text/plain", content="Foo"),
|
14
24
|
MessagePart(content_type="text/plain", content="Bar"),
|
15
|
-
]
|
25
|
+
],
|
26
|
+
created_at=timestamp,
|
27
|
+
completed_at=timestamp,
|
16
28
|
),
|
17
29
|
)
|
18
30
|
],
|
@@ -29,9 +41,15 @@ def test_message_add(first: Message, second: Message, result: Message) -> None:
|
|
29
41
|
parts=[
|
30
42
|
MessagePart(content_type="text/plain", content="Foo"),
|
31
43
|
MessagePart(content_type="text/plain", content="Bar"),
|
32
|
-
]
|
44
|
+
],
|
45
|
+
created_at=timestamp,
|
46
|
+
completed_at=timestamp,
|
47
|
+
),
|
48
|
+
Message(
|
49
|
+
parts=[MessagePart(content_type="text/plain", content="FooBar")],
|
50
|
+
created_at=timestamp,
|
51
|
+
completed_at=timestamp,
|
33
52
|
),
|
34
|
-
Message(parts=[MessagePart(content_type="text/plain", content="FooBar")]),
|
35
53
|
),
|
36
54
|
(
|
37
55
|
Message(
|
@@ -40,14 +58,18 @@ def test_message_add(first: Message, second: Message, result: Message) -> None:
|
|
40
58
|
MessagePart(content_type="text/html", content="<head>"),
|
41
59
|
MessagePart(content_type="text/plain", content="Foo"),
|
42
60
|
MessagePart(content_type="text/plain", content="Bar"),
|
43
|
-
]
|
61
|
+
],
|
62
|
+
created_at=timestamp,
|
63
|
+
completed_at=timestamp,
|
44
64
|
),
|
45
65
|
Message(
|
46
66
|
parts=[
|
47
67
|
MessagePart(content_type="text/plain", content="Foo"),
|
48
68
|
MessagePart(content_type="text/html", content="<head>"),
|
49
69
|
MessagePart(content_type="text/plain", content="FooBar"),
|
50
|
-
]
|
70
|
+
],
|
71
|
+
created_at=timestamp,
|
72
|
+
completed_at=timestamp,
|
51
73
|
),
|
52
74
|
),
|
53
75
|
],
|
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
|