Skip to content

Commit c1856da

Browse files
committed
Merge branch 'master' into 1973-refactor-create-start-inspect-methods
2 parents b4bc5b2 + e8383ed commit c1856da

File tree

78 files changed

+3403
-532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+3403
-532
lines changed

.github/actions/setup-simcore-env/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ inputs:
1010
uv-version:
1111
description: 'UV version to use'
1212
required: false
13-
default: '0.7.x'
13+
default: '0.8.x'
1414

1515
cache-dependency-glob:
1616
description: 'Glob pattern for cache dependency files'

Makefile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,31 @@ export DOCKER_REGISTRY ?= itisfoundation
8989

9090
MAKEFILES_WITH_OPENAPI_SPECS := $(shell find . -mindepth 2 -type f -name 'Makefile' -not -path '*/.*' -exec grep -l '^openapi-specs:' {} \; | xargs realpath)
9191

92+
# WSL 2 tricks
93+
define _check_wsl_mirroring
94+
$(shell \
95+
if [ "$(IS_WSL2)" = "WSL2" ]; then \
96+
win_user=$$(powershell.exe '$$env:UserName' | tr -d '\r' | tail -n 1 | xargs); \
97+
config_path="/mnt/c/Users/$$win_user/.wslconfig"; \
98+
if [ -f "$$config_path" ] && grep -q "networkingMode.*=.*mirrored" "$$config_path" 2>/dev/null; then \
99+
echo "true"; \
100+
else \
101+
echo "false"; \
102+
fi; \
103+
else \
104+
echo "false"; \
105+
fi \
106+
)
107+
endef
108+
109+
WSL_MIRRORED := $(_check_wsl_mirroring)
110+
111+
112+
ifeq ($(WSL_MIRRORED),true)
113+
get_my_ip := 127.0.0.1
114+
else
92115
get_my_ip := $(shell (hostname --all-ip-addresses || hostname -i) 2>/dev/null | cut --delimiter=" " --fields=1)
116+
endif
93117

94118
# NOTE: this is only for WSL2 as the WSL2 subsystem IP is changing on each reboot
95119
ifeq ($(IS_WSL2),WSL2)
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""Helper script to automatically generate OAS
2+
3+
This OAS are the source of truth
4+
"""
5+
6+
# pylint: disable=redefined-outer-name
7+
# pylint: disable=unused-argument
8+
# pylint: disable=unused-variable
9+
# pylint: disable=too-many-arguments
10+
11+
12+
from typing import Annotated
13+
14+
from _common import as_query
15+
from fastapi import APIRouter, Depends, status
16+
from models_library.api_schemas_webserver.conversations import (
17+
ConversationMessagePatch,
18+
ConversationMessageRestGet,
19+
ConversationPatch,
20+
ConversationRestGet,
21+
)
22+
from models_library.generics import Envelope
23+
from models_library.rest_pagination import Page
24+
from simcore_service_webserver._meta import API_VTAG
25+
from simcore_service_webserver.conversations._controller._common import (
26+
ConversationPathParams,
27+
)
28+
from simcore_service_webserver.conversations._controller._conversations_messages_rest import (
29+
_ConversationMessageCreateBodyParams,
30+
_ConversationMessagePathParams,
31+
_ListConversationMessageQueryParams,
32+
)
33+
from simcore_service_webserver.conversations._controller._conversations_rest import (
34+
_ConversationsCreateBodyParams,
35+
_GetConversationsQueryParams,
36+
_ListConversationsQueryParams,
37+
)
38+
39+
router = APIRouter(
40+
prefix=f"/{API_VTAG}",
41+
tags=[
42+
"conversations",
43+
],
44+
)
45+
46+
47+
#
48+
# API entrypoints CONVERSATIONS
49+
#
50+
51+
52+
@router.post(
53+
"/conversations",
54+
response_model=Envelope[ConversationRestGet],
55+
status_code=status.HTTP_201_CREATED,
56+
)
57+
async def create_conversation(
58+
_body: _ConversationsCreateBodyParams,
59+
_query: Annotated[_GetConversationsQueryParams, Depends()],
60+
): ...
61+
62+
63+
@router.get(
64+
"/conversations",
65+
response_model=Page[ConversationRestGet],
66+
)
67+
async def list_conversations(
68+
_query: Annotated[_ListConversationsQueryParams, Depends()],
69+
): ...
70+
71+
72+
@router.put(
73+
"/conversations/{conversation_id}",
74+
response_model=Envelope[ConversationRestGet],
75+
)
76+
async def update_conversation(
77+
_params: Annotated[ConversationPathParams, Depends()],
78+
_body: ConversationPatch,
79+
_query: Annotated[as_query(_GetConversationsQueryParams), Depends()],
80+
): ...
81+
82+
83+
@router.delete(
84+
"/conversations/{conversation_id}",
85+
status_code=status.HTTP_204_NO_CONTENT,
86+
)
87+
async def delete_conversation(
88+
_params: Annotated[ConversationPathParams, Depends()],
89+
_query: Annotated[as_query(_GetConversationsQueryParams), Depends()],
90+
): ...
91+
92+
93+
@router.get(
94+
"/conversations/{conversation_id}",
95+
response_model=Envelope[ConversationRestGet],
96+
)
97+
async def get_conversation(
98+
_params: Annotated[ConversationPathParams, Depends()],
99+
_query: Annotated[as_query(_GetConversationsQueryParams), Depends()],
100+
): ...
101+
102+
103+
#
104+
# API entrypoints CONVERSATION MESSAGES
105+
#
106+
107+
108+
@router.post(
109+
"/conversations/{conversation_id}/messages",
110+
response_model=Envelope[ConversationMessageRestGet],
111+
status_code=status.HTTP_201_CREATED,
112+
)
113+
async def create_conversation_message(
114+
_params: Annotated[ConversationPathParams, Depends()],
115+
_body: _ConversationMessageCreateBodyParams,
116+
): ...
117+
118+
119+
@router.get(
120+
"/conversations/{conversation_id}/messages",
121+
response_model=Page[ConversationMessageRestGet],
122+
)
123+
async def list_conversation_messages(
124+
_params: Annotated[ConversationPathParams, Depends()],
125+
_query: Annotated[as_query(_ListConversationMessageQueryParams), Depends()],
126+
): ...
127+
128+
129+
@router.put(
130+
"/conversations/{conversation_id}/messages/{message_id}",
131+
response_model=Envelope[ConversationMessageRestGet],
132+
)
133+
async def update_conversation_message(
134+
_params: Annotated[_ConversationMessagePathParams, Depends()],
135+
_body: ConversationMessagePatch,
136+
): ...
137+
138+
139+
@router.delete(
140+
"/conversations/{conversation_id}/messages/{message_id}",
141+
status_code=status.HTTP_204_NO_CONTENT,
142+
)
143+
async def delete_conversation_message(
144+
_params: Annotated[_ConversationMessagePathParams, Depends()],
145+
): ...
146+
147+
148+
@router.get(
149+
"/conversations/{conversation_id}/messages/{message_id}",
150+
response_model=Envelope[ConversationMessageRestGet],
151+
)
152+
async def get_conversation_message(
153+
_params: Annotated[_ConversationMessagePathParams, Depends()],
154+
): ...

api/specs/web-server/_projects_conversations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from typing import Annotated
1313

1414
from fastapi import APIRouter, Depends, status
15-
from models_library.api_schemas_webserver.projects_conversations import (
15+
from models_library.api_schemas_webserver.conversations import (
1616
ConversationMessageRestGet,
1717
ConversationRestGet,
1818
)

api/specs/web-server/openapi.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
# core ---
2222
"_auth",
2323
"_auth_api_keys",
24+
"_conversations",
2425
"_groups",
2526
"_tags",
2627
"_tags_groups", # after _tags

packages/models-library/src/models_library/api_schemas_directorv2/dynamic_services_service.py

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from pathlib import Path
33

44
from pydantic import BaseModel, ConfigDict, Field
5+
from pydantic.config import JsonDict
56

67
from ..basic_types import PortInt
78
from ..projects import ProjectID
@@ -88,40 +89,45 @@ class RunningDynamicServiceDetails(ServiceDetails):
8889
alias="service_message",
8990
)
9091

92+
@staticmethod
93+
def _update_json_schema_extra(schema: JsonDict) -> None:
94+
schema.update(
95+
{
96+
"examples": [ # legacy
97+
{
98+
"service_key": "simcore/services/dynamic/raw-graphs",
99+
"service_version": "2.10.6",
100+
"user_id": 1,
101+
"project_id": "32fb4eb6-ab30-11ef-9ee4-0242ac140008",
102+
"service_uuid": "0cd049ba-cd6b-4a12-b416-a50c9bc8e7bb",
103+
"service_basepath": "/x/0cd049ba-cd6b-4a12-b416-a50c9bc8e7bb",
104+
"service_host": "raw-graphs_0cd049ba-cd6b-4a12-b416-a50c9bc8e7bb",
105+
"service_port": 4000,
106+
"published_port": None,
107+
"entry_point": "",
108+
"service_state": "running",
109+
"service_message": "",
110+
},
111+
# new style
112+
{
113+
"service_key": "simcore/services/dynamic/jupyter-math",
114+
"service_version": "3.0.3",
115+
"user_id": 1,
116+
"project_id": "32fb4eb6-ab30-11ef-9ee4-0242ac140008",
117+
"service_uuid": "6e3cad3a-eb64-43de-b476-9ac3c413fd9c",
118+
"boot_type": "V2",
119+
"service_host": "dy-sidecar_6e3cad3a-eb64-43de-b476-9ac3c413fd9c",
120+
"service_port": 8888,
121+
"service_state": "running",
122+
"service_message": "",
123+
},
124+
]
125+
}
126+
)
127+
91128
model_config = ConfigDict(
92129
ignored_types=(cached_property,),
93-
json_schema_extra={
94-
"examples": [
95-
# legacy
96-
{
97-
"service_key": "simcore/services/dynamic/raw-graphs",
98-
"service_version": "2.10.6",
99-
"user_id": 1,
100-
"project_id": "32fb4eb6-ab30-11ef-9ee4-0242ac140008",
101-
"service_uuid": "0cd049ba-cd6b-4a12-b416-a50c9bc8e7bb",
102-
"service_basepath": "/x/0cd049ba-cd6b-4a12-b416-a50c9bc8e7bb",
103-
"service_host": "raw-graphs_0cd049ba-cd6b-4a12-b416-a50c9bc8e7bb",
104-
"service_port": 4000,
105-
"published_port": None,
106-
"entry_point": "",
107-
"service_state": "running",
108-
"service_message": "",
109-
},
110-
# new style
111-
{
112-
"service_key": "simcore/services/dynamic/jupyter-math",
113-
"service_version": "3.0.3",
114-
"user_id": 1,
115-
"project_id": "32fb4eb6-ab30-11ef-9ee4-0242ac140008",
116-
"service_uuid": "6e3cad3a-eb64-43de-b476-9ac3c413fd9c",
117-
"boot_type": "V2",
118-
"service_host": "dy-sidecar_6e3cad3a-eb64-43de-b476-9ac3c413fd9c",
119-
"service_port": 8888,
120-
"service_state": "running",
121-
"service_message": "",
122-
},
123-
]
124-
},
130+
json_schema_extra=_update_json_schema_extra,
125131
)
126132

127133
@cached_property
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from ..projects import ProjectID
1717
from ._base import InputSchema, OutputSchema
1818

19-
### PROJECT CONVERSATION -------------------------------------------------------------------
19+
### CONVERSATION -------------------------------------------------------------------
2020

2121

2222
class ConversationRestGet(OutputSchema):
@@ -28,6 +28,7 @@ class ConversationRestGet(OutputSchema):
2828
type: ConversationType
2929
created: datetime
3030
modified: datetime
31+
extra_context: dict[str, str]
3132

3233
@classmethod
3334
def from_domain_model(cls, domain: ConversationGetDB) -> Self:
@@ -40,14 +41,15 @@ def from_domain_model(cls, domain: ConversationGetDB) -> Self:
4041
type=domain.type,
4142
created=domain.created,
4243
modified=domain.modified,
44+
extra_context=domain.extra_context,
4345
)
4446

4547

4648
class ConversationPatch(InputSchema):
4749
name: str | None = None
4850

4951

50-
### PROJECT CONVERSATION MESSAGES ---------------------------------------------------------------
52+
### CONVERSATION MESSAGES ---------------------------------------------------------------
5153

5254

5355
class ConversationMessageRestGet(OutputSchema):

packages/models-library/src/models_library/api_schemas_webserver/projects_nodes.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from typing import Annotated, Any, Literal, TypeAlias
33

44
from pydantic import ConfigDict, Field
5+
from pydantic.config import JsonDict
56

67
from ..access_rights import ExecutableAccessRights
78
from ..api_schemas_directorv2.dynamic_services import RetrieveDataOut
@@ -163,14 +164,20 @@ class NodeGetIdle(OutputSchema):
163164
def from_node_id(cls, node_id: NodeID) -> "NodeGetIdle":
164165
return cls(service_state="idle", service_uuid=node_id)
165166

166-
model_config = ConfigDict(
167-
json_schema_extra={
168-
"example": {
169-
"service_uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
170-
"service_state": "idle",
167+
@staticmethod
168+
def _update_json_schema_extra(schema: JsonDict) -> None:
169+
schema.update(
170+
{
171+
"examples": [
172+
{
173+
"service_uuid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
174+
"service_state": "idle",
175+
}
176+
]
171177
}
172-
}
173-
)
178+
)
179+
180+
model_config = ConfigDict(json_schema_extra=_update_json_schema_extra)
174181

175182

176183
class NodeGetUnknown(OutputSchema):

packages/models-library/src/models_library/conversations.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
22
from enum import auto
3-
from typing import Annotated, TypeAlias
3+
from typing import Annotated, Any, TypeAlias
44
from uuid import UUID
55

66
from models_library.groups import GroupID
@@ -23,6 +23,7 @@ class ConversationType(StrAutoEnum):
2323
PROJECT_ANNOTATION = (
2424
auto() # Something like sticky note, can be located anywhere in the pipeline UI
2525
)
26+
SUPPORT = auto() # Support conversation
2627

2728

2829
class ConversationMessageType(StrAutoEnum):
@@ -44,6 +45,7 @@ class ConversationGetDB(BaseModel):
4445
project_uuid: ProjectID | None
4546
user_group_id: GroupID
4647
type: ConversationType
48+
extra_context: dict[str, Any]
4749

4850
# states
4951
created: datetime

0 commit comments

Comments
 (0)