truefoundry 0.4.1__py3-none-any.whl → 0.4.2__py3-none-any.whl

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.

Potentially problematic release.


This version of truefoundry might be problematic. Click here for more details.

Files changed (38) hide show
  1. truefoundry/common/auth_service_client.py +14 -5
  2. truefoundry/common/constants.py +2 -1
  3. truefoundry/common/credential_file_manager.py +4 -3
  4. truefoundry/common/credential_provider.py +4 -5
  5. truefoundry/common/servicefoundry_client.py +14 -7
  6. truefoundry/common/utils.py +59 -10
  7. truefoundry/deploy/auto_gen/models.py +11 -5
  8. truefoundry/deploy/builder/__init__.py +2 -2
  9. truefoundry/deploy/builder/builders/tfy_notebook_buildpack/__init__.py +7 -1
  10. truefoundry/deploy/builder/builders/tfy_notebook_buildpack/dockerfile_template.py +25 -12
  11. truefoundry/deploy/builder/builders/tfy_python_buildpack/__init__.py +8 -2
  12. truefoundry/deploy/builder/builders/tfy_python_buildpack/dockerfile_template.py +26 -3
  13. truefoundry/deploy/builder/constants.py +7 -0
  14. truefoundry/deploy/builder/utils.py +32 -0
  15. truefoundry/deploy/cli/commands/deploy_command.py +46 -2
  16. truefoundry/deploy/cli/util.py +4 -1
  17. truefoundry/deploy/lib/auth/servicefoundry_session.py +4 -2
  18. truefoundry/deploy/lib/clients/servicefoundry_client.py +3 -1
  19. truefoundry/deploy/lib/session.py +6 -6
  20. truefoundry/deploy/v2/lib/patched_models.py +4 -0
  21. truefoundry/ml/autogen/client/__init__.py +3 -0
  22. truefoundry/ml/autogen/client/api/mlfoundry_artifacts_api.py +163 -0
  23. truefoundry/ml/autogen/client/models/__init__.py +3 -0
  24. truefoundry/ml/autogen/client/models/delete_files_for_dataset_request_dto.py +68 -0
  25. truefoundry/ml/autogen/client_README.md +2 -0
  26. truefoundry/ml/autogen/entities/artifacts.py +286 -0
  27. truefoundry/ml/clients/servicefoundry_client.py +2 -4
  28. truefoundry/ml/log_types/artifacts/artifact.py +59 -1
  29. truefoundry/ml/mlfoundry_api.py +48 -3
  30. truefoundry/ml/mlfoundry_run.py +33 -16
  31. truefoundry/ml/run_utils.py +0 -14
  32. truefoundry/ml/session.py +9 -8
  33. truefoundry/workflow/example/hello_world_package/workflow.py +2 -2
  34. truefoundry/workflow/example/package/test_workflow.py +14 -15
  35. {truefoundry-0.4.1.dist-info → truefoundry-0.4.2.dist-info}/METADATA +1 -2
  36. {truefoundry-0.4.1.dist-info → truefoundry-0.4.2.dist-info}/RECORD +38 -34
  37. {truefoundry-0.4.1.dist-info → truefoundry-0.4.2.dist-info}/WHEEL +0 -0
  38. {truefoundry-0.4.1.dist-info → truefoundry-0.4.2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,286 @@
1
+ # generated by datamodel-codegen:
2
+ # filename: artifacts.json
3
+ # timestamp: 2024-09-12T13:40:36+00:00
4
+
5
+ from __future__ import annotations
6
+
7
+ from enum import Enum
8
+ from typing import Any, Dict, List, Literal, Optional, Union
9
+
10
+ from truefoundry.pydantic_v1 import BaseModel, Field, constr
11
+
12
+
13
+ class Agent(BaseModel):
14
+ type: Literal["agent"] = Field(..., description="+value=agent")
15
+ name: constr(regex=r"^[a-zA-Z][a-zA-Z0-9\-]{1,30}[a-zA-Z0-9]$") = Field(
16
+ ..., description="Names cannot repeat accross agent\n+uiType=Hidden"
17
+ )
18
+ available_tools: List[constr(min_length=1)] = Field(
19
+ ..., description="+sort=30\n+uiType=Hidden"
20
+ )
21
+ goal: constr(min_length=1, max_length=128) = Field(
22
+ ..., description="+sort=10\n+uiType=TextArea"
23
+ )
24
+ instruction: constr(min_length=1, max_length=2620) = Field(
25
+ ...,
26
+ description='`instruction` is the system prompt for now. (2.5 * 1024)\n+sort=20\n+uiType=AgentInstructions\n+uiProps={"helpText":"Use the syntax ${Tool FQN} to reference a tool, and ${AGENT FQN} to reference another agent"}',
27
+ )
28
+ model_id: constr(min_length=1) = Field(
29
+ ...,
30
+ description='+sort=40\n+uiType=EnabledModelSelector\n+uiProps={"searchable":true,"modelType":"chat","providerType":"openai"}',
31
+ )
32
+
33
+
34
+ class Method(str, Enum):
35
+ """
36
+ +sort=50
37
+ +uiType=Hidden
38
+ """
39
+
40
+ get = "get"
41
+ post = "post"
42
+ put = "put"
43
+ delete = "delete"
44
+ patch = "patch"
45
+
46
+
47
+ class AgentWithFQN(Agent):
48
+ id: str
49
+ fqn: str
50
+
51
+
52
+ class MimeType(str, Enum):
53
+ """
54
+ +label=MIME Type
55
+ +usage=MIME type of the content
56
+ """
57
+
58
+ text_plain = "text/plain"
59
+ application_json = "application/json"
60
+ image_png = "image/png"
61
+ image_jpeg = "image/jpeg"
62
+ application_x_directory = "application/x-directory"
63
+
64
+
65
+ class BlobStorageReference(BaseModel):
66
+ """
67
+ +usage=Blob Storage Location
68
+ +label=Blob Storage Location
69
+ +docs=Defines the structure for blob storage content references, including type, path, and mime_type
70
+ """
71
+
72
+ type: Literal["blob-storage"]
73
+ path: constr(regex=r"^.{1,}$") = Field(
74
+ ..., description="+label=Path\n+usage=Path to the content in blob storage"
75
+ )
76
+ mime_type: MimeType = Field(
77
+ ..., description="+label=MIME Type\n+usage=MIME type of the content"
78
+ )
79
+
80
+
81
+ class ImageUrl(BaseModel):
82
+ """
83
+ +label=URL for the image
84
+ +usage=The URL for the image, must be a non-empty valid HTTPS URL or a data URL
85
+ """
86
+
87
+ url: Union[
88
+ constr(
89
+ regex=r"^\b((https?://)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}(?:[-a-zA-Z0-9()@:%_\+.~#?&/=]*)|data:image/[a-zA-Z]+;base64,[a-zA-Z0-9+/=\s]+)$"
90
+ ),
91
+ BlobStorageReference,
92
+ ] = Field(
93
+ ...,
94
+ description="+label=URL for the image\n+usage=The URL for the image, must be a non-empty valid HTTPS URL or a data URL",
95
+ )
96
+
97
+
98
+ class ImageContentPart(BaseModel):
99
+ """
100
+ +usage=Image URL
101
+ +label=Image URL
102
+ """
103
+
104
+ type: Literal["image_url"]
105
+ image_url: ImageUrl = Field(
106
+ ...,
107
+ description="+label=URL for the image\n+usage=The URL for the image, must be a non-empty valid HTTPS URL or a data URL",
108
+ )
109
+
110
+
111
+ class Parameters(BaseModel):
112
+ """
113
+ +usage=Parameters for the provider
114
+ +label=Parameters
115
+ +docs=Key-value pairs to store additional parameters for the provider
116
+ """
117
+
118
+ max_tokens: Optional[int] = None
119
+ temperature: Optional[float] = None
120
+ top_k: Optional[float] = None
121
+ top_p: Optional[float] = None
122
+ stop: Optional[Union[List[str], str]] = None
123
+
124
+
125
+ class ModelConfiguration(BaseModel):
126
+ """
127
+ +label=Model Configuration
128
+ +icon=fa-cogs:#326ce5
129
+ +message=Configuration details for the provider and corresponding config
130
+ +usage=Define the provider and its configuration
131
+ +docs=Configuration settings specific to the provider, including model settings and other parameters.
132
+ """
133
+
134
+ provider: str = Field(
135
+ ...,
136
+ description='+label=Provider Name\n+usage=Name of the provider, must be non-empty, e.g., "openai", "google_gemini"',
137
+ )
138
+ model: constr(regex=r"^[a-zA-Z][a-zA-Z0-9\-]{1,30}[a-zA-Z0-9]$") = Field(
139
+ ..., description="+label=Model name\n+usage=Model name, must be non-empty"
140
+ )
141
+ parameters: Optional[Parameters] = Field(
142
+ None,
143
+ description="+usage=Parameters for the provider\n+label=Parameters\n+docs=Key-value pairs to store additional parameters for the provider",
144
+ )
145
+ extra_parameters: Optional[Dict[str, Any]] = Field(
146
+ None,
147
+ description="+usage=Extra parameters for the provider\n+label=Extra Parameters\n+docs=Additional parameters for the provider",
148
+ )
149
+
150
+
151
+ class SystemMessage(BaseModel):
152
+ """
153
+ +usage=System message
154
+ +docs=Defines the structure of a system message, including role and content
155
+ +label=System Message
156
+ """
157
+
158
+ role: Literal["system"]
159
+ content: Union[constr(regex=r"^.[\s\S]*$"), BlobStorageReference] = Field(
160
+ ..., description="+label=Content\n+usage=Text content for the system message"
161
+ )
162
+ name: Optional[str] = Field(
163
+ None, description="+label=Name\n+usage=Name of the system"
164
+ )
165
+
166
+
167
+ class TextContentPart(BaseModel):
168
+ """
169
+ +usage=Text content
170
+ +label=Text content
171
+ """
172
+
173
+ type: Literal["text"]
174
+ text: Union[constr(regex=r"^.[\s\S]*$"), BlobStorageReference]
175
+
176
+
177
+ class UserMessage(BaseModel):
178
+ """
179
+ +usage=User message
180
+ +docs=Defines the structure of a user message, including role and content
181
+ +label=User Message
182
+ """
183
+
184
+ role: Literal["user"]
185
+ content: Union[
186
+ constr(regex=r"^.[\s\S]*$"),
187
+ BlobStorageReference,
188
+ List[Union[TextContentPart, ImageContentPart]],
189
+ ] = Field(
190
+ ..., description="+label=Content\n+usage=Text content for the user message"
191
+ )
192
+ name: Optional[str] = Field(
193
+ None, description="+label=Name\n+usage=Name of the user message"
194
+ )
195
+
196
+
197
+ class AgentOpenAPITool(BaseModel):
198
+ type: Literal["openapi-tool"] = Field(..., description="+value=openapi-tool")
199
+ name: constr(regex=r"^[a-zA-Z][a-zA-Z0-9\-]{1,30}[a-zA-Z0-9]$") = Field(
200
+ ..., description="Names cannot repeat accross tools\n+uiType=Hidden"
201
+ )
202
+ description: constr(min_length=1, max_length=128) = Field(
203
+ ..., description="+sort=10\n+uiType=TextArea"
204
+ )
205
+ openapi_spec: Union[BlobStorageReference, Dict[str, Any]] = Field(
206
+ ..., description="+sort=20\n+uiType=OpenapiSchema"
207
+ )
208
+ base_url: constr(
209
+ regex=r"^(https?://)?(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}(?:[-a-zA-Z0-9()@:%_\+.~#?&/=]*)$"
210
+ ) = Field(..., description="+sort=30")
211
+ path: constr(min_length=1) = Field(
212
+ ...,
213
+ description="+sort=40\n+uiType=MethodPathSelector\n+label=Method + Path\n+usage=Select one Method and Path for this tool",
214
+ )
215
+ method: Method = Field(..., description="+sort=50\n+uiType=Hidden")
216
+ headers: Optional[Dict[str, str]] = Field(
217
+ None,
218
+ description='+sort=60\n+uiType=KV\n+uiProps={"allowSecrets":true,"secretConfig":{"enableNew":true,"hideOptions":true}}',
219
+ )
220
+
221
+
222
+ class AgentOpenAPIToolWithFQN(AgentOpenAPITool):
223
+ id: str
224
+ fqn: str
225
+
226
+
227
+ class AssistantMessage(BaseModel):
228
+ """
229
+ +usage=Assistant message
230
+ +docs=Defines the structure of an assistant message, including role and content
231
+ +label=Assistant Message
232
+ """
233
+
234
+ role: Literal["assistant"]
235
+ content: Union[constr(regex=r"^.[\s\S]*$"), BlobStorageReference] = Field(
236
+ ..., description="+label=Content\n+usage=Text content for the assistant message"
237
+ )
238
+ name: Optional[str] = Field(
239
+ None, description="+label=Name\n+usage=Name of the assistant message"
240
+ )
241
+
242
+
243
+ class BasePrompt(BaseModel):
244
+ """
245
+ Main prompt structure
246
+ """
247
+
248
+ name: constr(regex=r"^[a-zA-Z][a-zA-Z0-9-_]{0,254}[a-zA-Z0-9]$") = Field(
249
+ ...,
250
+ description="+label=Prompt Name\n+icon=fa-desktop:#326ce5\n+message=Alphanumeric word, may contain '-' with a maximum length of 256 characters\n+sort=1000\n+usage=Name of the Prompt. This uniquely identifies it in the workspace.\n+docs=The unique name for the prompt, consisting of alphanumeric characters and dashes, max length 100.",
251
+ )
252
+ description: Optional[constr(min_length=1, max_length=512)] = Field(
253
+ None,
254
+ description="+label=Description\n+icon=fa-desktop:#326ce5\n+message=Description in a maximum of 512 characters\n+sort=2000\n+usage=Description of the prompt\n+docs=An optional description for the prompt, with a maximum length of 512 characters.\n+optional",
255
+ )
256
+ model_configuration: ModelConfiguration
257
+ metadata: Dict[str, str] = Field(
258
+ ...,
259
+ description="+label=Metadata\n+icon=fa-info-circle:#326ce5\n+message=Additional metadata for the prompt\n+sort=7000\n+usage=Define additional metadata for the prompt\n+docs=Key-value pairs to store additional metadata related to the prompt.",
260
+ )
261
+
262
+
263
+ class ChatPrompt(BasePrompt):
264
+ type: Literal["chat_prompt"] = Field(
265
+ ...,
266
+ description='+label=Type\n+icon=fa-desktop:#326ce5\n+message=Type of the prompt\n+sort=3000\n+usage=Type of the prompt\n+docs=Type of the prompt, set to "chat_prompt"\n+default="chat_prompt"',
267
+ )
268
+ messages: List[Union[SystemMessage, AssistantMessage, UserMessage]] = Field(
269
+ ...,
270
+ description="+sort=4000\n+usage=Chat completion messages\n+label=Messages in the chat conversation\n+message=Chat completion messages\n+usage=List of messages in the chat conversation, must be non-empty\n+docs=Messages that define the chat conversation, including system, assistant, and user messages.",
271
+ )
272
+ variables: Optional[Dict[str, Optional[str]]] = Field(
273
+ None,
274
+ description="+label=Variables\n+usage=Variables for the chat completion messages to be used in the prompt messages\n+sort=5000",
275
+ )
276
+
277
+
278
+ class AgentApp(BaseModel):
279
+ type: Literal["agent-app"] = Field(..., description="+value=agent-app")
280
+ tools: List[AgentOpenAPIToolWithFQN]
281
+ agents: List[AgentWithFQN]
282
+ root_agent: constr(min_length=1)
283
+
284
+
285
+ class Artifacts(BaseModel):
286
+ __root__: Union[ChatPrompt, AgentOpenAPITool, Agent, AgentApp]
@@ -12,15 +12,13 @@ from truefoundry.ml.clients.entities import (
12
12
  )
13
13
  from truefoundry.ml.clients.utils import http_request_safe
14
14
  from truefoundry.ml.exceptions import MlFoundryException
15
- from truefoundry.ml.run_utils import append_servicefoundry_path_to_tracking_uri
16
15
 
17
16
 
18
17
  class ServiceFoundryServiceClient(BaseServiceFoundryServiceClient):
18
+ # TODO (chiragjn): Rename tracking_uri to tfy_host
19
19
  def __init__(self, tracking_uri: str, token: Optional[str] = None):
20
20
  super().__init__(base_url=tracking_uri)
21
- self.host_creds = HostCreds(
22
- host=append_servicefoundry_path_to_tracking_uri(tracking_uri), token=token
23
- )
21
+ self.host_creds = HostCreds(host=self._api_server_url, token=token)
24
22
 
25
23
  def get_integration_from_id(self, integration_id: str):
26
24
  integration_id = integration_id or ""
@@ -5,7 +5,7 @@ import os
5
5
  import tempfile
6
6
  import uuid
7
7
  from pathlib import Path
8
- from typing import TYPE_CHECKING, Any, Dict, NamedTuple, Optional, Tuple, Union
8
+ from typing import TYPE_CHECKING, Any, Dict, List, NamedTuple, Optional, Tuple, Union
9
9
 
10
10
  from truefoundry.ml.artifact.truefoundry_artifact_repo import (
11
11
  ArtifactIdentifier,
@@ -25,6 +25,7 @@ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
25
25
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
26
26
  InternalMetadata as InternalMetadataDto,
27
27
  )
28
+ from truefoundry.ml.autogen.entities.artifacts import ChatPrompt
28
29
  from truefoundry.ml.exceptions import MlFoundryException
29
30
  from truefoundry.ml.log_types.artifacts.constants import INTERNAL_METADATA_PATH
30
31
  from truefoundry.ml.log_types.artifacts.utils import (
@@ -351,6 +352,63 @@ class ArtifactVersion:
351
352
  self._set_mutable_attrs()
352
353
 
353
354
 
355
+ class ChatPromptVersion(ArtifactVersion):
356
+ def __init__(self, artifact_version: ArtifactVersionDto, artifact: ArtifactDto):
357
+ if artifact.type != ArtifactType.CHAT_PROMPT:
358
+ raise ValueError(
359
+ f"{artifact_version.fqn!r} is not a chat prompt type artifact"
360
+ )
361
+ super().__init__(
362
+ artifact_version=artifact_version,
363
+ artifact=artifact,
364
+ )
365
+ self._chat_prompt = ChatPrompt.parse_obj(
366
+ artifact_version.internal_metadata.to_dict()
367
+ )
368
+
369
+ @classmethod
370
+ def from_fqn(cls, fqn: str) -> "ChatPromptVersion":
371
+ api_client = _get_api_client()
372
+ mlfoundry_artifacts_api = MlfoundryArtifactsApi(api_client=api_client)
373
+ _artifact_version = mlfoundry_artifacts_api.get_artifact_version_by_fqn_get(
374
+ fqn=fqn
375
+ )
376
+ artifact_version = _artifact_version.artifact_version
377
+ _artifact = mlfoundry_artifacts_api.get_artifact_by_id_get(
378
+ id=artifact_version.artifact_id
379
+ )
380
+ return cls(
381
+ artifact_version=_artifact_version.artifact_version,
382
+ artifact=_artifact.artifact,
383
+ )
384
+
385
+ @property
386
+ def model(self) -> str:
387
+ return self._chat_prompt.model_configuration.model
388
+
389
+ @property
390
+ def provider(self) -> str:
391
+ return self._chat_prompt.model_configuration.provider
392
+
393
+ @property
394
+ def messages(self) -> List[Dict[str, Any]]:
395
+ return [message.dict() for message in self._chat_prompt.messages]
396
+
397
+ @property
398
+ def parameters(self) -> Dict[str, Any]:
399
+ _parameters = self._chat_prompt.model_configuration.parameters
400
+ return _parameters.dict(exclude_unset=True) if _parameters else {}
401
+
402
+ @property
403
+ def extra_parameters(self) -> Dict[str, Any]:
404
+ _extra_parameters = self._chat_prompt.model_configuration.extra_parameters
405
+ return _extra_parameters.dict(exclude_unset=True) if _extra_parameters else {}
406
+
407
+ @property
408
+ def variables(self) -> Dict[str, Any]:
409
+ return self._chat_prompt.variables or {}
410
+
411
+
354
412
  def _log_artifact_version_helper(
355
413
  run: "MlFoundryRun",
356
414
  name: str,
@@ -7,6 +7,7 @@ from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union
7
7
  import coolname
8
8
  import pandas as pd
9
9
 
10
+ from truefoundry.common.utils import relogin_error_message
10
11
  from truefoundry.ml import constants, env_vars
11
12
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
12
13
  ArtifactDto,
@@ -34,7 +35,11 @@ from truefoundry.ml.clients.servicefoundry_client import ServiceFoundryServiceCl
34
35
  from truefoundry.ml.enums import ModelFramework, ViewType
35
36
  from truefoundry.ml.exceptions import MlFoundryException
36
37
  from truefoundry.ml.internal_namespace import NAMESPACE
37
- from truefoundry.ml.log_types.artifacts.artifact import ArtifactPath, ArtifactVersion
38
+ from truefoundry.ml.log_types.artifacts.artifact import (
39
+ ArtifactPath,
40
+ ArtifactVersion,
41
+ ChatPromptVersion,
42
+ )
38
43
  from truefoundry.ml.log_types.artifacts.dataset import DataDirectory
39
44
  from truefoundry.ml.log_types.artifacts.general_artifact import _log_artifact_version
40
45
  from truefoundry.ml.log_types.artifacts.model import ModelVersion, _log_model_version
@@ -209,8 +214,9 @@ class MlFoundry:
209
214
  session = get_active_session()
210
215
  if session is None:
211
216
  raise MlFoundryException(
212
- "No active session found. Perhaps you are not logged in?\n"
213
- "Please log in using `tfy login [--host HOST] --relogin"
217
+ relogin_error_message(
218
+ "No active session found. Perhaps you are not logged in?",
219
+ )
214
220
  )
215
221
  servicefoundry_client = ServiceFoundryServiceClient(
216
222
  tracking_uri=self.get_tracking_uri(),
@@ -1554,6 +1560,45 @@ class MlFoundry:
1554
1560
  if not datasets or not page_token:
1555
1561
  done = True
1556
1562
 
1563
+ def get_chat_prompt_version_by_fqn(self, fqn: str) -> ChatPromptVersion:
1564
+ """
1565
+ Get the prompt by prompt version FQN
1566
+ Args:
1567
+ fqn (str): Fully qualified name of the chat prompt version.
1568
+ Returns:
1569
+ ChatPromptVersion: An instance of the ChatPromptVersion class with the fetched prompt details.
1570
+
1571
+ Examples:
1572
+ ```python
1573
+ from truefoundry.ml import get_client
1574
+ client = get_client()
1575
+
1576
+ # Get the chat prompt by FQN
1577
+ fqn = 'chat_prompt:truefoundry/prompt-demo/demo-prompt-1:2'
1578
+ chat_prompt = client.get_chat_prompt_version_by_fqn(fqn=fqn)
1579
+
1580
+ # Check the chat prompt values
1581
+ print(chat_prompt)
1582
+
1583
+ # Use with OpenAI client
1584
+ from openai import OpenAI
1585
+ openai_client = OpenAI(api_key="api_key")
1586
+
1587
+ # Make the OpenAI call
1588
+ response = openai_client.chat.completions.create(
1589
+ model=chat_prompt.model,
1590
+ messages=chat_prompt.messages,
1591
+ **chat_prompt.parameters,
1592
+ **chat_prompt.extra_parameters
1593
+ )
1594
+
1595
+ # Extract the content from the response
1596
+ response_content = response.choices[0].message.content
1597
+ print(response_content)
1598
+ ```
1599
+ """
1600
+ return ChatPromptVersion.from_fqn(fqn=fqn)
1601
+
1557
1602
 
1558
1603
  def get_client() -> MlFoundry:
1559
1604
  """Initializes and returns the mlfoundry client.
@@ -19,6 +19,7 @@ from typing import (
19
19
  from urllib.parse import urljoin, urlsplit
20
20
 
21
21
  from truefoundry import version
22
+ from truefoundry.common.utils import relogin_error_message
22
23
  from truefoundry.ml import constants, enums
23
24
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
24
25
  ArtifactType,
@@ -51,6 +52,8 @@ from truefoundry.ml.run_utils import ParamsType, flatten_dict, process_params
51
52
  from truefoundry.ml.session import ACTIVE_RUNS, _get_api_client, get_active_session
52
53
  from truefoundry.ml.validation_utils import (
53
54
  MAX_ENTITY_KEY_LENGTH,
55
+ MAX_METRICS_PER_BATCH,
56
+ MAX_PARAMS_TAGS_PER_BATCH,
54
57
  _validate_batch_log_data,
55
58
  )
56
59
 
@@ -222,8 +225,9 @@ class MlFoundryRun:
222
225
  session = get_active_session()
223
226
  if session is None:
224
227
  raise MlFoundryException(
225
- "No active session found. Perhaps you are not logged in?\n"
226
- "Please log in using `tfy login [--host HOST] --relogin"
228
+ relogin_error_message(
229
+ "No active session found. Perhaps you are not logged in?",
230
+ )
227
231
  )
228
232
  base_url = "{uri.scheme}://{uri.netloc}/".format(
229
233
  uri=urlsplit(session.tracking_uri)
@@ -636,12 +640,16 @@ class MlFoundryRun:
636
640
  return
637
641
 
638
642
  try:
639
- _validate_batch_log_data(metrics=metrics, params=[], tags=[])
640
- self._runs_api.log_run_batch_post(
641
- log_batch_request_dto=LogBatchRequestDto(
642
- run_id=self.run_id, metrics=metrics, params=[], tags=[]
643
+ for i in range(0, len(metrics), MAX_METRICS_PER_BATCH):
644
+ metrics_batch = metrics[i : i + MAX_METRICS_PER_BATCH]
645
+
646
+ _validate_batch_log_data(metrics=metrics_batch, params=[], tags=[])
647
+
648
+ self._runs_api.log_run_batch_post(
649
+ log_batch_request_dto=LogBatchRequestDto(
650
+ run_id=self.run_id, metrics=metrics_batch, params=[], tags=[]
651
+ )
643
652
  )
644
- )
645
653
  except Exception as e:
646
654
  raise MlFoundryException(str(e)) from e
647
655
 
@@ -723,12 +731,17 @@ class MlFoundryRun:
723
731
  if len(params) == 0:
724
732
  logger.warning("Cannot log empty params dictionary")
725
733
 
726
- _validate_batch_log_data(metrics=[], params=params, tags=[])
727
- self._runs_api.log_run_batch_post(
728
- log_batch_request_dto=LogBatchRequestDto(
729
- run_id=self.run_id, metrics=[], params=params, tags=[]
734
+ for i in range(0, len(params), MAX_PARAMS_TAGS_PER_BATCH):
735
+ params_batch = params[i : i + MAX_PARAMS_TAGS_PER_BATCH]
736
+
737
+ _validate_batch_log_data(metrics=[], params=params_batch, tags=[])
738
+ logger.debug("Logging parameters: %s", params_batch)
739
+
740
+ self._runs_api.log_run_batch_post(
741
+ log_batch_request_dto=LogBatchRequestDto(
742
+ run_id=self.run_id, metrics=[], params=params_batch, tags=[]
743
+ )
730
744
  )
731
- )
732
745
  except Exception as e:
733
746
  raise MlFoundryException(str(e)) from e
734
747
  logger.info("Parameters logged successfully")
@@ -765,11 +778,15 @@ class MlFoundryRun:
765
778
  tags_arr = [
766
779
  RunTagDto(key=key, value=str(value)) for key, value in tags.items()
767
780
  ]
768
- self._runs_api.log_run_batch_post(
769
- log_batch_request_dto=LogBatchRequestDto(
770
- run_id=self.run_id, metrics=[], params=[], tags=tags_arr
781
+ for i in range(0, len(tags_arr), MAX_PARAMS_TAGS_PER_BATCH):
782
+ tags_batch = tags_arr[i : i + MAX_PARAMS_TAGS_PER_BATCH]
783
+
784
+ _validate_batch_log_data(metrics=[], params=[], tags=tags_batch)
785
+ self._runs_api.log_run_batch_post(
786
+ log_batch_request_dto=LogBatchRequestDto(
787
+ run_id=self.run_id, metrics=[], params=[], tags=tags_batch
788
+ )
771
789
  )
772
- )
773
790
  except Exception as e:
774
791
  raise MlFoundryException(str(e)) from e
775
792
  logger.info("Tags set successfully")
@@ -1,9 +1,7 @@
1
1
  import argparse
2
2
  import importlib
3
3
  import json
4
- import os
5
4
  from typing import Any, Dict, List, Mapping, Optional, Tuple, Union
6
- from urllib.parse import urljoin, urlsplit
7
5
 
8
6
  import numpy as np
9
7
 
@@ -21,18 +19,6 @@ def get_module(
21
19
  raise MlFoundryException(msg) from ex
22
20
 
23
21
 
24
- def append_path_to_rest_tracking_uri(tracking_uri: str):
25
- if urlsplit(tracking_uri).netloc.startswith("localhost"):
26
- return tracking_uri
27
- return urljoin(tracking_uri, "/api/ml")
28
-
29
-
30
- def append_servicefoundry_path_to_tracking_uri(tracking_uri: str):
31
- if urlsplit(tracking_uri).netloc.startswith("localhost"):
32
- return os.getenv("SERVICEFOUNDRY_SERVER_URL")
33
- return urljoin(tracking_uri, "/api/svc")
34
-
35
-
36
22
  class NumpyEncoder(json.JSONEncoder):
37
23
  """Special json encoder for numpy types"""
38
24
 
truefoundry/ml/session.py CHANGED
@@ -10,6 +10,7 @@ from truefoundry.common.credential_provider import (
10
10
  )
11
11
  from truefoundry.common.entities import Token, UserInfo
12
12
  from truefoundry.common.request_utils import urllib3_retry
13
+ from truefoundry.common.utils import get_tfy_servers_config, relogin_error_message
13
14
  from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
14
15
  ApiClient,
15
16
  Configuration,
@@ -17,9 +18,6 @@ from truefoundry.ml.autogen.client import ( # type: ignore[attr-defined]
17
18
  from truefoundry.ml.clients.entities import HostCreds
18
19
  from truefoundry.ml.exceptions import MlFoundryException
19
20
  from truefoundry.ml.logger import logger
20
- from truefoundry.ml.run_utils import (
21
- append_path_to_rest_tracking_uri,
22
- )
23
21
 
24
22
  if TYPE_CHECKING:
25
23
  from truefoundry.ml.mlfoundry_run import MlFoundryRun
@@ -83,6 +81,7 @@ class Session:
83
81
  self._assert_not_closed()
84
82
  return self._user_info
85
83
 
84
+ # TODO (chiragjn): Rename tracking_uri to tfy_host
86
85
  @property
87
86
  def tracking_uri(self) -> str:
88
87
  return self._cred_provider.base_url
@@ -97,7 +96,7 @@ class Session:
97
96
  )
98
97
 
99
98
  def get_host_creds(self) -> HostCreds:
100
- tracking_uri = append_path_to_rest_tracking_uri(self._cred_provider.base_url)
99
+ tracking_uri = get_tfy_servers_config(self.tracking_uri).mlfoundry_server_url
101
100
  return HostCreds(
102
101
  host=tracking_uri, token=self._cred_provider.token.access_token
103
102
  )
@@ -120,8 +119,9 @@ def _get_api_client(
120
119
  return ApiClient()
121
120
  else:
122
121
  raise MlFoundryException(
123
- "No active session found. Perhaps you are not logged in?\n"
124
- "Please log in using `tfy login [--host HOST] --relogin"
122
+ relogin_error_message(
123
+ "No active session found. Perhaps you are not logged in?",
124
+ )
125
125
  )
126
126
 
127
127
  creds = session.get_host_creds()
@@ -144,8 +144,9 @@ def init_session() -> Session:
144
144
  break
145
145
  if final_cred_provider is None:
146
146
  raise MlFoundryException(
147
- "Please login using `tfy login` command "
148
- "or `truefoundry.login()` function call"
147
+ relogin_error_message(
148
+ "No active session found. Perhaps you are not logged in?",
149
+ )
149
150
  )
150
151
  new_session = Session(cred_provider=final_cred_provider)
151
152
 
@@ -5,9 +5,9 @@ from truefoundry.workflow import PythonTaskConfig, TaskPythonBuild, task, workfl
5
5
  task_config=PythonTaskConfig(
6
6
  image=TaskPythonBuild(
7
7
  python_version="3.9",
8
- pip_packages=["truefoundry[workflow]==0.3.0rc7"],
8
+ pip_packages=["truefoundry[workflow]"],
9
9
  ),
10
- service_account="tfy-flyte-dataplane-devtest-s3",
10
+ service_account="tfy-workflows-sa",
11
11
  )
12
12
  )
13
13
  def say_hello() -> str: