Skip to content

Commit 31d5f72

Browse files
authored
Removes "assistant instance" terminology (#262)
In favor of just "assistant" Additionally: - removes unused workflow code and DB tables - adds participant.metadata for storing conversation state per user
1 parent 0dd996f commit 31d5f72

26 files changed

Lines changed: 175 additions & 2220 deletions

File tree

.github/workflows/workbench-service.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches: ["main"]
66
paths:
77
- "workbench-service/**"
8+
- "libraries/python/semantic-workbench-assistant/**"
89
- "libraries/python/semantic-workbench-api-model/**"
910
- "tools/docker/**"
1011
- ".github/workflows/workbench-service.yml"
@@ -13,6 +14,7 @@ on:
1314
branches: ["main"]
1415
paths:
1516
- "workbench-service/**"
17+
- "libraries/python/semantic-workbench-assistant/**"
1618
- "libraries/python/semantic-workbench-api-model/**"
1719
- "tools/docker/**"
1820
- ".github/workflows/workbench-service.yml"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Workspace files allow us to manage multiple projects within a monorepo more effe
6666
- Bring your own llm api keys
6767
- Use VS Code > `Run and Debug` (Ctrl/Cmd+Shift+D) > `examples: python-02-simple-chatbot` to start the example chatbot assistant. Either set your keys in your .env file or after creating the assistant as described below, select it and provide the keys in the configuration page.
6868

69-
## Open the Workbench and create an Assistant instance
69+
## Open the Workbench and create an Assistant
7070

7171
Open the app in your browser at [`https://localhost:4000`](https://localhost:4000). When you first log into the Semantic Workbench, follow these steps to get started:
7272

assistants/skill-assistant/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ The Skill Assistant serves as a demonstration of integrating the Skill Library w
44

55
## Overview
66

7-
[skill_controller.py](assistant/skill_controller.py) file is responsible for managing the assistant instances. It includes functionality to create and retrieve assistants, configure chat drivers, and map skill events to the Semantic Workbench.
7+
[skill_controller.py](assistant/skill_controller.py) file is responsible for managing the assistants. It includes functionality to create and retrieve assistants, configure chat drivers, and map skill events to the Semantic Workbench.
88

9-
- AssistantRegistry: Manages multiple assistant instances, each associated with a unique conversation.
9+
- AssistantRegistry: Manages multiple assistants, each associated with a unique conversation.
1010
- \_event_mapper: Maps skill events to message types understood by the Semantic Workbench.
1111
- create_assistant: Defines how to create and configure a new assistant.
1212

assistants/skill-assistant/assistant/assistant_registry.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
# TODO: Put this registry in the skill library.
1515
class AssistantRegistry:
1616
"""
17-
This class handles the creation and management of skill assistant instances
18-
for this service. Each conversation has its own assistant and we start each
19-
assistant in it's own thread so that all events are able to be
20-
asynchronously passed on to the Semantic Workbench.
17+
This class handles the creation and management of skill assistants for this service.
18+
Each conversation has its own assistant and we start each assistant in it's own
19+
thread so that all events are able to be asynchronously passed on to the Semantic
20+
Workbench.
2121
"""
2222

2323
def __init__(self) -> None:

docs/WORKBENCH_APP.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ The Semantic Workbench interface dashboard includes sections for your assistants
5252

5353
Select any of your assistants to access and update the assistant's configuration. Select an existing conversation or create a new one to start interacting with your assistants.
5454

55-
# Assistant Instances
55+
# Assistants
5656

57-
Creating and configuring assistants in the Semantic Workbench allows you to utilize different AI functionalities tailored to specific needs. Note that you can create multiple instances of a single assistant service, each with its own configuration.
57+
Creating and configuring assistants in the Semantic Workbench allows you to utilize different AI functionalities tailored to specific needs. Note that you can create multiple assistants, all back by a single assistant service, each with its own configuration.
5858

5959
## Creating a New Assistant
6060

61-
Creating a new assistant in the Semantic Workbench is straightforward. Begin by clicking on the `New Assistant` button on the dashboard. You will be presented with the available assistant services to choose from. Select the one that best suits your needs. You can accept the default name or choose your own then click `Save` to create the instance.
61+
Creating a new assistant in the Semantic Workbench is straightforward. Begin by clicking on the `New Assistant` button on the dashboard. You will be presented with the available assistant services to choose from. Select the one that best suits your needs. You can accept the default name or choose your own then click `Save` to create the assistant.
6262

6363
## Configuring Assistants
6464

@@ -91,7 +91,7 @@ You have the ability to invite additional people to either observe or participat
9191

9292
## Creating a New Conversation
9393

94-
To start a new conversation with your assistant, click on its instance and then click `New Conversation`. Provide a title for the conversation and click `Save`.
94+
To start a new conversation with your assistant, click on it and then click `New Conversation`. Provide a title for the conversation and click `Save`.
9595

9696
## Basics of Conversations
9797

@@ -152,11 +152,11 @@ When you provide someone with a link to copy a conversation it will copy the con
152152
* Second person follows the link later, they get the additional messages and data you added before they followed the link.
153153

154154
### Duplicating conversation
155-
From the conversation list you can also duplicate them. This is useful for experimenting with taking conversations in different directions, or using one as a common base for further explorations.
155+
From the conversation list you can also duplicate them. This is useful for experimenting with taking conversations in different directions, or using one as a common base for further explorations.
156156

157157
![Duplicate Conversation](images/conversation_duplicate.png)
158158

159-
Note that this will also copy the assistant instance the conversation is a part of as there is some state associated between the assistant and the conversation.
159+
Note that this will also copy the assistant that the conversation is a part of as there is some state associated between the assistant and the conversation.
160160

161161
### Exporting and importing conversations
162162

libraries/python/semantic-workbench-api-model/semantic_workbench_api_model/assistant_service_client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def __init__(
7878
)
7979

8080

81-
class AssistantInstanceClient:
81+
class AssistantClient:
8282
def __init__(self, httpx_client_factory: Callable[[], httpx.AsyncClient]) -> None:
8383
self._client = httpx_client_factory()
8484

@@ -157,7 +157,7 @@ async def put_config(self, updated_config: ConfigPutRequestModel) -> ConfigRespo
157157
return ConfigResponseModel.model_validate(http_response.json())
158158

159159
@asynccontextmanager
160-
async def get_exported_instance_data(self) -> AsyncGenerator[AsyncIterator[bytes], Any]:
160+
async def get_exported_data(self) -> AsyncGenerator[AsyncIterator[bytes], Any]:
161161
try:
162162
http_response = await self._client.send(self._client.build_request("GET", "/export-data"), stream=True)
163163
except httpx.RequestError as e:
@@ -266,7 +266,7 @@ async def __aexit__(
266266
async def aclose(self) -> None:
267267
await self._client.aclose()
268268

269-
async def put_assistant_instance(
269+
async def put_assistant(
270270
self,
271271
assistant_id: uuid.UUID,
272272
request: AssistantPutRequestModel,
@@ -284,7 +284,7 @@ async def put_assistant_instance(
284284
if not response.is_success:
285285
raise AssistantResponseError(response)
286286

287-
async def delete_assistant_instance(self, assistant_id: uuid.UUID) -> None:
287+
async def delete_assistant(self, assistant_id: uuid.UUID) -> None:
288288
try:
289289
response = await self._client.delete(f"/{assistant_id}")
290290
if response.status_code == httpx.codes.NOT_FOUND:
@@ -331,7 +331,7 @@ def _client(self, *additional_paths: str) -> httpx.AsyncClient:
331331
def for_service(self) -> AssistantServiceClient:
332332
return AssistantServiceClient(httpx_client_factory=self._client)
333333

334-
def for_assistant_instance(self, assistant_id: uuid.UUID) -> AssistantInstanceClient:
335-
return AssistantInstanceClient(
334+
def for_assistant(self, assistant_id: uuid.UUID) -> AssistantClient:
335+
return AssistantClient(
336336
httpx_client_factory=lambda: self._client(str(assistant_id)),
337337
)

libraries/python/semantic-workbench-api-model/semantic_workbench_api_model/workbench_model.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,6 @@ class ParticipantRole(StrEnum):
6363
service = "service"
6464

6565

66-
class ParticipantStatus(BaseModel):
67-
timestamp: datetime.datetime = Field(default_factory=lambda: datetime.datetime.now(datetime.UTC))
68-
message: str | None = None
69-
70-
7166
class ConversationPermission(StrEnum):
7267
read_write = "read_write"
7368
read = "read"
@@ -84,6 +79,7 @@ class ConversationParticipant(BaseModel):
8479
active_participant: bool
8580
online: bool | None = None
8681
conversation_permission: ConversationPermission
82+
metadata: dict[str, Any]
8783

8884

8985
class ConversationParticipantList(BaseModel):
@@ -459,6 +455,7 @@ class UpdateParticipant(BaseModel):
459455

460456
status: str | None = None
461457
active_participant: bool | None = None
458+
metadata: dict[str, Any] | None = None
462459

463460

464461
class ConversationEventType(StrEnum):

libraries/python/semantic-workbench-api-model/semantic_workbench_api_model/workbench_service_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ def from_headers(headers: Mapping[str, str]) -> AssistantServiceRequestHeaders:
4040

4141

4242
@dataclass
43-
class AssistantInstanceRequestHeaders:
43+
class AssistantRequestHeaders:
4444
assistant_id: uuid.UUID | None
4545

4646
def to_headers(self) -> Mapping[str, str]:
4747
return {HEADER_ASSISTANT_ID: str(self.assistant_id)}
4848

4949
@staticmethod
50-
def from_headers(headers: Mapping[str, str]) -> AssistantInstanceRequestHeaders:
50+
def from_headers(headers: Mapping[str, str]) -> AssistantRequestHeaders:
5151
assistant_id: uuid.UUID | None = None
5252
with suppress(ValueError):
5353
assistant_id = uuid.UUID(headers.get(HEADER_ASSISTANT_ID) or "")
54-
return AssistantInstanceRequestHeaders(
54+
return AssistantRequestHeaders(
5555
assistant_id=assistant_id,
5656
)
5757

@@ -480,7 +480,7 @@ def __init__(
480480
self._assistant_service_id = assistant_service_id
481481
self._api_key = api_key
482482

483-
def _client(self, *headers: AssistantServiceRequestHeaders | AssistantInstanceRequestHeaders) -> httpx.AsyncClient:
483+
def _client(self, *headers: AssistantServiceRequestHeaders | AssistantRequestHeaders) -> httpx.AsyncClient:
484484
client = httpx.AsyncClient(
485485
transport=httpx_transport_factory(),
486486
base_url=self._base_url,
@@ -505,7 +505,7 @@ def for_conversation(self, assistant_id: str, conversation_id: str) -> Conversat
505505
conversation_id=conversation_id,
506506
httpx_client_factory=lambda: self._client(
507507
AssistantServiceRequestHeaders(assistant_service_id=self._assistant_service_id, api_key=self._api_key),
508-
AssistantInstanceRequestHeaders(assistant_id=uuid.UUID(assistant_id)),
508+
AssistantRequestHeaders(assistant_id=uuid.UUID(assistant_id)),
509509
),
510510
)
511511

libraries/python/semantic-workbench-assistant/semantic_workbench_assistant/assistant_service.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,7 @@ async def get_service_description() -> assistant_model.ServiceInfoModel:
307307
@app.put(
308308
"/{assistant_id}",
309309
description=(
310-
"Connect an assistant instance to the workbench, optionally"
311-
" providing exported-data to restore the assistant"
310+
"Connect an assistant to the workbench, optionally providing exported-data to restore the assistant"
312311
),
313312
)
314313
async def put_assistant(
@@ -328,21 +327,21 @@ async def put_assistant(
328327

329328
@app.get(
330329
"/{assistant_id}",
331-
description="Get an assistant instance",
330+
description="Get an assistant",
332331
)
333332
async def get_assistant(assistant_id: str) -> assistant_model.AssistantResponseModel:
334333
return await service.get_assistant(assistant_id)
335334

336335
@app.delete(
337336
"/{assistant_id}",
338-
description="Delete an assistant instance",
337+
description="Delete an assistant",
339338
)
340339
async def delete_assistant(assistant_id: str) -> None:
341340
return await service.delete_assistant(assistant_id)
342341

343342
@app.get(
344343
"/{assistant_id}/export-data",
345-
description="Export all data for this assistant instance",
344+
description="Export all data for this assistant",
346345
)
347346
async def export_assistant_data(assistant_id: str) -> Response:
348347
response = await service.export_assistant_data(assistant_id)
@@ -356,14 +355,14 @@ async def export_assistant_data(assistant_id: str) -> Response:
356355

357356
@app.get(
358357
"/{assistant_id}/config",
359-
description="Get config for this assistant instance",
358+
description="Get config for this assistant",
360359
)
361360
async def get_config(assistant_id: str) -> assistant_model.ConfigResponseModel:
362361
return await service.get_config(assistant_id)
363362

364363
@app.put(
365364
"/{assistant_id}/config",
366-
description="Set config for this assistant instance",
365+
description="Set config for this assistant",
367366
)
368367
async def put_config(
369368
assistant_id: str, updated_config: assistant_model.ConfigPutRequestModel
@@ -373,7 +372,7 @@ async def put_config(
373372
@app.put(
374373
"/{assistant_id}/conversations/{conversation_id}",
375374
description=(
376-
"Join an assistant instance to a workbench conversation, optionally"
375+
"Join an assistant to a workbench conversation, optionally"
377376
" providing exported-data to restore the conversation"
378377
),
379378
)

libraries/python/semantic-workbench-assistant/tests/test_assistant_app.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,9 @@ async def on_chat_message(
118118

119119
client_builder = assistant_service_client.AssistantServiceClientBuilder("https://fake", "")
120120
service_client = client_builder.for_service()
121-
instance_client = client_builder.for_assistant_instance(assistant_id)
121+
instance_client = client_builder.for_assistant(assistant_id)
122122

123-
await service_client.put_assistant_instance(
124-
assistant_id=assistant_id, request=assistant_request, from_export=None
125-
)
123+
await service_client.put_assistant(assistant_id=assistant_id, request=assistant_request, from_export=None)
126124

127125
assert assistant_created_calls == 1
128126

@@ -263,11 +261,9 @@ async def get(self, context: ConversationContext) -> AssistantConversationInspec
263261

264262
client_builder = assistant_service_client.AssistantServiceClientBuilder("https://fake", "")
265263
service_client = client_builder.for_service()
266-
instance_client = client_builder.for_assistant_instance(assistant_id)
264+
instance_client = client_builder.for_assistant(assistant_id)
267265

268-
await service_client.put_assistant_instance(
269-
assistant_id=assistant_id, request=assistant_request, from_export=None
270-
)
266+
await service_client.put_assistant(assistant_id=assistant_id, request=assistant_request, from_export=None)
271267
await instance_client.put_conversation(
272268
request=assistant_model.ConversationPutRequestModel(
273269
id=str(conversation_id),
@@ -334,11 +330,9 @@ async def import_(self, conversation_context: ConversationContext, stream: IO[by
334330

335331
client_builder = assistant_service_client.AssistantServiceClientBuilder("https://fake", "")
336332
service_client = client_builder.for_service()
337-
instance_client = client_builder.for_assistant_instance(assistant_id)
333+
instance_client = client_builder.for_assistant(assistant_id)
338334

339-
await service_client.put_assistant_instance(
340-
assistant_id=assistant_id, request=assistant_request, from_export=None
341-
)
335+
await service_client.put_assistant(assistant_id=assistant_id, request=assistant_request, from_export=None)
342336

343337
conversation_id = uuid.uuid4()
344338

@@ -415,11 +409,9 @@ class TestConfigModel(BaseModel):
415409

416410
client_builder = assistant_service_client.AssistantServiceClientBuilder("https://fake", "")
417411
service_client = client_builder.for_service()
418-
instance_client = client_builder.for_assistant_instance(assistant_id)
412+
instance_client = client_builder.for_assistant(assistant_id)
419413

420-
await service_client.put_assistant_instance(
421-
assistant_id=assistant_id, request=assistant_request, from_export=None
422-
)
414+
await service_client.put_assistant(assistant_id=assistant_id, request=assistant_request, from_export=None)
423415

424416
response = await instance_client.get_config()
425417
assert response == assistant_model.ConfigResponseModel(
@@ -463,7 +455,7 @@ class TestConfigModel(BaseModel):
463455
temp_dir_path = pathlib.Path(temp_dir)
464456
export_file_path = temp_dir_path / "export.zip"
465457
with export_file_path.open("wb") as f:
466-
async with instance_client.get_exported_instance_data() as response:
458+
async with instance_client.get_exported_data() as response:
467459
async for chunk in response:
468460
f.write(chunk)
469461

0 commit comments

Comments
 (0)