salesforce-data-customcode 6.0.2__py3-none-any.whl → 6.0.3.dev1__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.
- datacustomcode/__init__.py +15 -0
- datacustomcode/cli.py +3 -6
- datacustomcode/client.py +92 -1
- datacustomcode/config.yaml +3 -0
- datacustomcode/einstein_platform_config.py +8 -4
- datacustomcode/einstein_predictions_config.py +1 -1
- datacustomcode/function/feature_types/chunking.py +1 -0
- datacustomcode/io/writer/base.py +1 -11
- datacustomcode/llm_gateway/__init__.py +6 -0
- datacustomcode/{proxy/base.py → llm_gateway/errors.py} +17 -5
- datacustomcode/llm_gateway/spark_base.py +53 -0
- datacustomcode/llm_gateway/spark_default.py +125 -0
- datacustomcode/llm_gateway_config.py +43 -2
- datacustomcode/templates/function/.devcontainer/devcontainer.json +1 -1
- datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py +3 -0
- datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py +3 -0
- datacustomcode/templates/function/payload/entrypoint.py +11 -12
- datacustomcode/templates/script/.devcontainer/devcontainer.json +1 -1
- datacustomcode/templates/script/payload/entrypoint.py +26 -0
- datacustomcode/token_provider.py +36 -70
- {salesforce_data_customcode-6.0.2.dist-info → salesforce_data_customcode-6.0.3.dev1.dist-info}/METADATA +47 -1
- {salesforce_data_customcode-6.0.2.dist-info → salesforce_data_customcode-6.0.3.dev1.dist-info}/RECORD +25 -26
- datacustomcode/proxy/__init__.py +0 -14
- datacustomcode/proxy/client/__init__.py +0 -14
- datacustomcode/proxy/client/base.py +0 -32
- {salesforce_data_customcode-6.0.2.dist-info → salesforce_data_customcode-6.0.3.dev1.dist-info}/WHEEL +0 -0
- {salesforce_data_customcode-6.0.2.dist-info → salesforce_data_customcode-6.0.3.dev1.dist-info}/entry_points.txt +0 -0
- {salesforce_data_customcode-6.0.2.dist-info → salesforce_data_customcode-6.0.3.dev1.dist-info}/licenses/LICENSE.txt +0 -0
datacustomcode/__init__.py
CHANGED
|
@@ -17,8 +17,11 @@ __all__ = [
|
|
|
17
17
|
"AuthType",
|
|
18
18
|
"Client",
|
|
19
19
|
"Credentials",
|
|
20
|
+
"DefaultSparkLLMGateway",
|
|
20
21
|
"PrintDataCloudWriter",
|
|
21
22
|
"QueryAPIDataCloudReader",
|
|
23
|
+
"SparkLLMGateway",
|
|
24
|
+
"llm_gateway_generate_text_col",
|
|
22
25
|
]
|
|
23
26
|
|
|
24
27
|
|
|
@@ -44,4 +47,16 @@ def __getattr__(name: str):
|
|
|
44
47
|
from datacustomcode.io.reader.query_api import QueryAPIDataCloudReader
|
|
45
48
|
|
|
46
49
|
return QueryAPIDataCloudReader
|
|
50
|
+
elif name == "SparkLLMGateway":
|
|
51
|
+
from datacustomcode.llm_gateway import SparkLLMGateway
|
|
52
|
+
|
|
53
|
+
return SparkLLMGateway
|
|
54
|
+
elif name == "DefaultSparkLLMGateway":
|
|
55
|
+
from datacustomcode.llm_gateway import DefaultSparkLLMGateway
|
|
56
|
+
|
|
57
|
+
return DefaultSparkLLMGateway
|
|
58
|
+
elif name == "llm_gateway_generate_text_col":
|
|
59
|
+
from datacustomcode.client import llm_gateway_generate_text_col
|
|
60
|
+
|
|
61
|
+
return llm_gateway_generate_text_col
|
|
47
62
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
datacustomcode/cli.py
CHANGED
|
@@ -198,7 +198,6 @@ def zip(path: str, network: str):
|
|
|
198
198
|
default=None,
|
|
199
199
|
help="SF CLI org alias or username. Fetches credentials via `sf org display`.",
|
|
200
200
|
)
|
|
201
|
-
@click.option("--use-in-feature", default=None, hidden=True, deprecated=True)
|
|
202
201
|
def deploy(
|
|
203
202
|
path: str,
|
|
204
203
|
name: str,
|
|
@@ -208,7 +207,6 @@ def deploy(
|
|
|
208
207
|
profile: str,
|
|
209
208
|
network: str,
|
|
210
209
|
sf_cli_org: Optional[str],
|
|
211
|
-
use_in_feature: Optional[str],
|
|
212
210
|
):
|
|
213
211
|
from datacustomcode.constants import USE_IN_FEATURE_MAPPING_FOR_CONNECT_API
|
|
214
212
|
from datacustomcode.deploy import (
|
|
@@ -251,14 +249,13 @@ def deploy(
|
|
|
251
249
|
logger.info(f"Inferred use_in_feature: {use_in_feature}")
|
|
252
250
|
else:
|
|
253
251
|
click.secho(
|
|
254
|
-
"Error:
|
|
255
|
-
"
|
|
256
|
-
"SearchIndexChunkingV1Response in function signature.",
|
|
252
|
+
"Error: Could not infer function invoke options. "
|
|
253
|
+
"Please provide --use-in-feature",
|
|
257
254
|
fg="red",
|
|
258
255
|
)
|
|
259
256
|
raise click.Abort()
|
|
260
257
|
|
|
261
|
-
# Map feature names to
|
|
258
|
+
# Map user-provided feature names to API names
|
|
262
259
|
mapped_feature = USE_IN_FEATURE_MAPPING_FOR_CONNECT_API.get(
|
|
263
260
|
use_in_feature, use_in_feature
|
|
264
261
|
)
|
datacustomcode/client.py
CHANGED
|
@@ -18,24 +18,75 @@ from enum import Enum
|
|
|
18
18
|
from typing import (
|
|
19
19
|
TYPE_CHECKING,
|
|
20
20
|
ClassVar,
|
|
21
|
+
Dict,
|
|
21
22
|
Optional,
|
|
23
|
+
Union,
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
from datacustomcode.config import config
|
|
25
27
|
from datacustomcode.file.path.default import DefaultFindFilePath
|
|
26
28
|
from datacustomcode.io.reader.base import BaseDataCloudReader
|
|
29
|
+
from datacustomcode.llm_gateway_config import spark_llm_gateway_config
|
|
27
30
|
from datacustomcode.spark.default import DefaultSparkSessionProvider
|
|
28
31
|
|
|
29
32
|
if TYPE_CHECKING:
|
|
30
33
|
from pathlib import Path
|
|
31
34
|
|
|
32
|
-
from pyspark.sql import DataFrame as PySparkDataFrame
|
|
35
|
+
from pyspark.sql import Column, DataFrame as PySparkDataFrame
|
|
33
36
|
|
|
34
37
|
from datacustomcode.io.reader.base import BaseDataCloudReader
|
|
35
38
|
from datacustomcode.io.writer.base import BaseDataCloudWriter, WriteMode
|
|
39
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
36
40
|
from datacustomcode.spark.base import BaseSparkSessionProvider
|
|
37
41
|
|
|
38
42
|
|
|
43
|
+
def _build_spark_llm_gateway() -> "SparkLLMGateway":
|
|
44
|
+
"""Instantiate the SDK-configured :class:`SparkLLMGateway`.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
RuntimeError: If no ``spark_llm_gateway_config`` has been loaded.
|
|
48
|
+
"""
|
|
49
|
+
cfg = spark_llm_gateway_config.spark_llm_gateway_config
|
|
50
|
+
if cfg is None:
|
|
51
|
+
raise RuntimeError(
|
|
52
|
+
"spark_llm_gateway_config is not configured. Add a "
|
|
53
|
+
"'spark_llm_gateway_config' section to config.yaml."
|
|
54
|
+
)
|
|
55
|
+
return cfg.to_object()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def llm_gateway_generate_text_col(
|
|
59
|
+
template: str,
|
|
60
|
+
values: Union[Dict[str, "Column"], "Column"],
|
|
61
|
+
model_id: Optional[str] = None,
|
|
62
|
+
) -> "Column":
|
|
63
|
+
"""Build a Spark Column that runs the LLM Gateway per row.
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
|
|
67
|
+
>>> df.withColumn(
|
|
68
|
+
... "greeting__c",
|
|
69
|
+
... llm_gateway_generate_text_col(
|
|
70
|
+
... "In one sentence, greet {name} from {city}.",
|
|
71
|
+
... {"name": col("name__c"), "city": col("homecity__c")},
|
|
72
|
+
... model_id="sfdc_ai__DefaultGPT4Omni",
|
|
73
|
+
... ),
|
|
74
|
+
... )
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
template: The prompt template, with ``{field}`` placeholders matching
|
|
78
|
+
keys in ``values``. Substitution uses ``str.format``.
|
|
79
|
+
values: Either a mapping from placeholder name to Spark ``Column``, or
|
|
80
|
+
a single ``Column`` whose value is already a struct.
|
|
81
|
+
model_id: LLM model id. Defaults to ``sfdc_ai__DefaultGPT4Omni``.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
A Spark ``Column`` that, when evaluated, produces the generated text.
|
|
85
|
+
"""
|
|
86
|
+
gateway = Client()._get_spark_llm_gateway()
|
|
87
|
+
return gateway.llm_gateway_generate_text_col(template, values, model_id=model_id)
|
|
88
|
+
|
|
89
|
+
|
|
39
90
|
class DataCloudObjectType(Enum):
|
|
40
91
|
DLO = "dlo"
|
|
41
92
|
DMO = "dmo"
|
|
@@ -94,18 +145,21 @@ class Client:
|
|
|
94
145
|
finder: Find a file path
|
|
95
146
|
reader: A custom reader to use for reading Data Cloud objects.
|
|
96
147
|
writer: A custom writer to use for writing Data Cloud objects.
|
|
148
|
+
spark_llm_gateway: Optional custom :class:`SparkLLMGateway`.
|
|
97
149
|
|
|
98
150
|
Example:
|
|
99
151
|
>>> client = Client()
|
|
100
152
|
>>> file_path = client.find_file_path("data.csv")
|
|
101
153
|
>>> dlo = client.read_dlo("my_dlo")
|
|
102
154
|
>>> client.write_to_dmo("my_dmo", dlo)
|
|
155
|
+
>>> answer = client.llm_gateway_generate_text("Generate a greeting message")
|
|
103
156
|
"""
|
|
104
157
|
|
|
105
158
|
_instance: ClassVar[Optional[Client]] = None
|
|
106
159
|
_reader: BaseDataCloudReader
|
|
107
160
|
_writer: BaseDataCloudWriter
|
|
108
161
|
_file: DefaultFindFilePath
|
|
162
|
+
_spark_llm_gateway: Optional[SparkLLMGateway]
|
|
109
163
|
_data_layer_history: dict[DataCloudObjectType, set[str]]
|
|
110
164
|
_code_type: str
|
|
111
165
|
|
|
@@ -114,11 +168,13 @@ class Client:
|
|
|
114
168
|
reader: Optional[BaseDataCloudReader] = None,
|
|
115
169
|
writer: Optional[BaseDataCloudWriter] = None,
|
|
116
170
|
spark_provider: Optional[BaseSparkSessionProvider] = None,
|
|
171
|
+
spark_llm_gateway: Optional[SparkLLMGateway] = None,
|
|
117
172
|
code_type: str = "script",
|
|
118
173
|
) -> Client:
|
|
119
174
|
|
|
120
175
|
if cls._instance is None:
|
|
121
176
|
cls._instance = super().__new__(cls)
|
|
177
|
+
cls._instance._spark_llm_gateway = spark_llm_gateway
|
|
122
178
|
# Initialize Readers and Writers from config
|
|
123
179
|
# and/or provided reader and writer
|
|
124
180
|
if reader is None or writer is None:
|
|
@@ -225,6 +281,41 @@ class Client:
|
|
|
225
281
|
|
|
226
282
|
return self._file.find_file_path(file_name) # type: ignore[no-any-return]
|
|
227
283
|
|
|
284
|
+
def llm_gateway_generate_text(
|
|
285
|
+
self,
|
|
286
|
+
prompt: str,
|
|
287
|
+
model_id: Optional[str] = None,
|
|
288
|
+
) -> str:
|
|
289
|
+
"""Issue a one-shot LLM Gateway call. This is the scalar counterpart to
|
|
290
|
+
:func:`llm_gateway_generate_text_col`: it runs **once** — not per row.
|
|
291
|
+
Use the column helper method instead when you want to fan a prompt out across
|
|
292
|
+
every row of a DataFrame.
|
|
293
|
+
|
|
294
|
+
Example:
|
|
295
|
+
|
|
296
|
+
>>> response = Client().llm_gateway_generate_text(
|
|
297
|
+
... "Generate a greeting message"
|
|
298
|
+
... )
|
|
299
|
+
|
|
300
|
+
Args:
|
|
301
|
+
prompt: The literal prompt to send. Plain text — no
|
|
302
|
+
``{field}`` substitution is performed on this string.
|
|
303
|
+
model_id: LLM model id to target. Defaults to
|
|
304
|
+
``sfdc_ai__DefaultGPT4Omni`` when ``None``.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
The generated text as a plain Python ``str``; empty when the
|
|
308
|
+
gateway response carries no generated text.
|
|
309
|
+
"""
|
|
310
|
+
return self._get_spark_llm_gateway().llm_gateway_generate_text(
|
|
311
|
+
prompt, model_id=model_id
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
def _get_spark_llm_gateway(self) -> SparkLLMGateway:
|
|
315
|
+
if self._spark_llm_gateway is None:
|
|
316
|
+
self._spark_llm_gateway = _build_spark_llm_gateway()
|
|
317
|
+
return self._spark_llm_gateway
|
|
318
|
+
|
|
228
319
|
def _validate_data_layer_history_does_not_contain(
|
|
229
320
|
self, data_cloud_object_type: DataCloudObjectType
|
|
230
321
|
) -> None:
|
datacustomcode/config.yaml
CHANGED
|
@@ -15,20 +15,23 @@
|
|
|
15
15
|
|
|
16
16
|
from typing import (
|
|
17
17
|
ClassVar,
|
|
18
|
+
Generic,
|
|
18
19
|
Optional,
|
|
19
20
|
Type,
|
|
20
|
-
|
|
21
|
+
TypeVar,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
from datacustomcode.common_config import BaseObjectConfig
|
|
24
25
|
|
|
26
|
+
_T = TypeVar("_T")
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
|
|
29
|
+
class CredentialsObjectConfig(BaseObjectConfig, Generic[_T]):
|
|
27
30
|
type_to_create: ClassVar[Type]
|
|
28
31
|
credentials_profile: Optional[str] = None
|
|
29
32
|
sf_cli_org: Optional[str] = None
|
|
30
33
|
|
|
31
|
-
def to_object(self):
|
|
34
|
+
def to_object(self) -> _T:
|
|
32
35
|
"""Create an object instance, automatically including credentials in options"""
|
|
33
36
|
|
|
34
37
|
options = self.options.copy()
|
|
@@ -38,4 +41,5 @@ class CredentialsObjectConfig(BaseObjectConfig):
|
|
|
38
41
|
options["sf_cli_org"] = self.sf_cli_org
|
|
39
42
|
|
|
40
43
|
type_ = self.type_to_create.subclass_from_config_name(self.type_config_name)
|
|
41
|
-
|
|
44
|
+
instance: _T = type_(**options)
|
|
45
|
+
return instance
|
|
@@ -28,7 +28,7 @@ from datacustomcode.einstein_predictions.base import EinsteinPredictions
|
|
|
28
28
|
_E = TypeVar("_E", bound=EinsteinPredictions)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class EinsteinPredictionsObjectConfig(CredentialsObjectConfig, Generic[_E]):
|
|
31
|
+
class EinsteinPredictionsObjectConfig(CredentialsObjectConfig[_E], Generic[_E]):
|
|
32
32
|
type_to_create: ClassVar[Type[EinsteinPredictions]] = EinsteinPredictions # type: ignore[type-abstract]
|
|
33
33
|
|
|
34
34
|
|
datacustomcode/io/writer/base.py
CHANGED
|
@@ -27,21 +27,11 @@ if TYPE_CHECKING:
|
|
|
27
27
|
class WriteMode(str, Enum):
|
|
28
28
|
APPEND = "append"
|
|
29
29
|
OVERWRITE = "overwrite"
|
|
30
|
-
OVERWRITE_PARTITIONS = "overwrite_partitions"
|
|
30
|
+
OVERWRITE_PARTITIONS = "overwrite_partitions"
|
|
31
31
|
MERGE = "merge"
|
|
32
32
|
MERGE_UPSERT_DELETE = "merge_upsert_delete"
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
class MergeRecordType(str, Enum):
|
|
36
|
-
"""Values for the _merge_record_type column used by MERGE_UPSERT_DELETE."""
|
|
37
|
-
|
|
38
|
-
UPSERT = "UPSERT"
|
|
39
|
-
DELETE = "DELETE"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
MERGE_RECORD_TYPE_COLUMN = "_merge_record_type"
|
|
43
|
-
|
|
44
|
-
|
|
45
35
|
class BaseDataCloudWriter(BaseDataAccessLayer):
|
|
46
36
|
"""Base class for Data Cloud writers."""
|
|
47
37
|
|
|
@@ -15,8 +15,14 @@
|
|
|
15
15
|
|
|
16
16
|
from datacustomcode.llm_gateway.base import LLMGateway
|
|
17
17
|
from datacustomcode.llm_gateway.default import DefaultLLMGateway
|
|
18
|
+
from datacustomcode.llm_gateway.errors import LLMGatewayCallError
|
|
19
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
20
|
+
from datacustomcode.llm_gateway.spark_default import DefaultSparkLLMGateway
|
|
18
21
|
|
|
19
22
|
__all__ = [
|
|
20
23
|
"DefaultLLMGateway",
|
|
24
|
+
"DefaultSparkLLMGateway",
|
|
21
25
|
"LLMGateway",
|
|
26
|
+
"LLMGatewayCallError",
|
|
27
|
+
"SparkLLMGateway",
|
|
22
28
|
]
|
|
@@ -12,13 +12,25 @@
|
|
|
12
12
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
|
+
"""Exceptions raised by LLM Gateway implementations."""
|
|
16
|
+
|
|
15
17
|
from __future__ import annotations
|
|
16
18
|
|
|
17
|
-
from
|
|
19
|
+
from typing import Optional
|
|
18
20
|
|
|
19
|
-
from datacustomcode.mixin import UserExtendableNamedConfigMixin
|
|
20
21
|
|
|
22
|
+
class LLMGatewayCallError(RuntimeError):
|
|
23
|
+
"""Raised when an LLM Gateway call returns an error."""
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
message: str,
|
|
28
|
+
*,
|
|
29
|
+
status: Optional[object] = None,
|
|
30
|
+
error_code: Optional[str] = None,
|
|
31
|
+
error_message: Optional[str] = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
super().__init__(message)
|
|
34
|
+
self.status = status
|
|
35
|
+
self.error_code = error_code
|
|
36
|
+
self.error_message = error_message
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from abc import ABC, abstractmethod
|
|
18
|
+
from typing import (
|
|
19
|
+
TYPE_CHECKING,
|
|
20
|
+
Any,
|
|
21
|
+
Dict,
|
|
22
|
+
Optional,
|
|
23
|
+
Union,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from datacustomcode.mixin import UserExtendableNamedConfigMixin
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from pyspark.sql import Column
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SparkLLMGateway(ABC, UserExtendableNamedConfigMixin):
|
|
33
|
+
CONFIG_NAME: str
|
|
34
|
+
|
|
35
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def llm_gateway_generate_text(
|
|
40
|
+
self,
|
|
41
|
+
prompt: str,
|
|
42
|
+
model_id: Optional[str] = None,
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Issue a one-shot LLM Gateway call and return the generated text."""
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def llm_gateway_generate_text_col(
|
|
48
|
+
self,
|
|
49
|
+
template: str,
|
|
50
|
+
values: Union[Dict[str, "Column"], "Column"],
|
|
51
|
+
model_id: Optional[str] = None,
|
|
52
|
+
) -> "Column":
|
|
53
|
+
"""Build a Spark ``Column`` that invokes the LLM Gateway per row."""
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from typing import (
|
|
18
|
+
TYPE_CHECKING,
|
|
19
|
+
Any,
|
|
20
|
+
Dict,
|
|
21
|
+
Optional,
|
|
22
|
+
Union,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pyspark.sql import Column
|
|
29
|
+
|
|
30
|
+
from datacustomcode.llm_gateway.base import LLMGateway
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_DEFAULT_LLM_MODEL_ID = "sfdc_ai__DefaultGPT4Omni"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DefaultSparkLLMGateway(SparkLLMGateway):
|
|
37
|
+
|
|
38
|
+
CONFIG_NAME = "DefaultSparkLLMGateway"
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
llm_gateway: Optional["LLMGateway"] = None,
|
|
43
|
+
**kwargs: Any,
|
|
44
|
+
) -> None:
|
|
45
|
+
super().__init__(**kwargs)
|
|
46
|
+
if llm_gateway is None:
|
|
47
|
+
llm_gateway = _build_underlying_gateway()
|
|
48
|
+
self._llm_gateway: "LLMGateway" = llm_gateway
|
|
49
|
+
|
|
50
|
+
def llm_gateway_generate_text(
|
|
51
|
+
self,
|
|
52
|
+
prompt: str,
|
|
53
|
+
model_id: Optional[str] = None,
|
|
54
|
+
) -> str:
|
|
55
|
+
return _invoke_llm_gateway(self._llm_gateway, prompt, model_id)
|
|
56
|
+
|
|
57
|
+
def llm_gateway_generate_text_col(
|
|
58
|
+
self,
|
|
59
|
+
template: str,
|
|
60
|
+
values: Union[Dict[str, "Column"], "Column"],
|
|
61
|
+
model_id: Optional[str] = None,
|
|
62
|
+
) -> "Column":
|
|
63
|
+
|
|
64
|
+
from pyspark.sql.functions import struct, udf
|
|
65
|
+
from pyspark.sql.types import StringType
|
|
66
|
+
|
|
67
|
+
if isinstance(values, dict):
|
|
68
|
+
values_col = struct(*[v.alias(k) for k, v in values.items()])
|
|
69
|
+
else:
|
|
70
|
+
values_col = values
|
|
71
|
+
|
|
72
|
+
gateway = self._llm_gateway
|
|
73
|
+
|
|
74
|
+
def _generate(values_row: Any) -> str:
|
|
75
|
+
if values_row is None:
|
|
76
|
+
return ""
|
|
77
|
+
subs = (
|
|
78
|
+
values_row.asDict()
|
|
79
|
+
if hasattr(values_row, "asDict")
|
|
80
|
+
else dict(values_row)
|
|
81
|
+
)
|
|
82
|
+
prompt = template.format(**subs)
|
|
83
|
+
return _invoke_llm_gateway(gateway, prompt, model_id)
|
|
84
|
+
|
|
85
|
+
return udf(_generate, StringType())(values_col)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _build_underlying_gateway() -> "LLMGateway":
|
|
89
|
+
from datacustomcode.llm_gateway_config import llm_gateway_config
|
|
90
|
+
|
|
91
|
+
cfg = llm_gateway_config.llm_gateway_config
|
|
92
|
+
if cfg is None:
|
|
93
|
+
raise RuntimeError(
|
|
94
|
+
"llm_gateway_config is not configured. Add an 'llm_gateway_config' "
|
|
95
|
+
"section to config.yaml."
|
|
96
|
+
)
|
|
97
|
+
return cfg.to_object()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _invoke_llm_gateway(
|
|
101
|
+
gateway: "LLMGateway",
|
|
102
|
+
prompt: str,
|
|
103
|
+
model_id: Optional[str],
|
|
104
|
+
) -> str:
|
|
105
|
+
from datacustomcode.llm_gateway.errors import LLMGatewayCallError
|
|
106
|
+
from datacustomcode.llm_gateway.types.generate_text_request_builder import (
|
|
107
|
+
GenerateTextRequestBuilder,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
builder = (
|
|
111
|
+
GenerateTextRequestBuilder()
|
|
112
|
+
.set_prompt(prompt)
|
|
113
|
+
.set_model(model_id or _DEFAULT_LLM_MODEL_ID)
|
|
114
|
+
)
|
|
115
|
+
response = gateway.generate_text(builder.build())
|
|
116
|
+
if response.is_error:
|
|
117
|
+
raise LLMGatewayCallError(
|
|
118
|
+
f"LLM Gateway call failed: status_code={response.status_code}, "
|
|
119
|
+
f"error_code={response.error_code!r}, "
|
|
120
|
+
f"message={response.data!r}",
|
|
121
|
+
status=response.status_code,
|
|
122
|
+
error_code=response.error_code or None,
|
|
123
|
+
error_message=str(response.data) if response.data else None,
|
|
124
|
+
)
|
|
125
|
+
return response.text
|
|
@@ -21,14 +21,20 @@ from typing import (
|
|
|
21
21
|
Union,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
from datacustomcode.common_config import
|
|
24
|
+
from datacustomcode.common_config import (
|
|
25
|
+
BaseConfig,
|
|
26
|
+
BaseObjectConfig,
|
|
27
|
+
default_config_file,
|
|
28
|
+
)
|
|
25
29
|
from datacustomcode.einstein_platform_config import CredentialsObjectConfig
|
|
26
30
|
from datacustomcode.llm_gateway.base import LLMGateway
|
|
31
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
27
32
|
|
|
28
33
|
_E = TypeVar("_E", bound=LLMGateway)
|
|
34
|
+
_S = TypeVar("_S", bound=SparkLLMGateway)
|
|
29
35
|
|
|
30
36
|
|
|
31
|
-
class LLMGatewayObjectConfig(CredentialsObjectConfig, Generic[_E]):
|
|
37
|
+
class LLMGatewayObjectConfig(CredentialsObjectConfig[_E], Generic[_E]):
|
|
32
38
|
type_to_create: ClassVar[Type[LLMGateway]] = LLMGateway # type: ignore[type-abstract]
|
|
33
39
|
|
|
34
40
|
|
|
@@ -52,6 +58,41 @@ class LLMGatewayConfig(BaseConfig):
|
|
|
52
58
|
return self
|
|
53
59
|
|
|
54
60
|
|
|
61
|
+
class SparkLLMGatewayObjectConfig(BaseObjectConfig, Generic[_S]):
|
|
62
|
+
type_to_create: ClassVar[Type[SparkLLMGateway]] = SparkLLMGateway # type: ignore[type-abstract]
|
|
63
|
+
|
|
64
|
+
def to_object(self) -> SparkLLMGateway:
|
|
65
|
+
type_ = self.type_to_create.subclass_from_config_name(self.type_config_name)
|
|
66
|
+
return type_(**self.options)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class SparkLLMGatewayConfig(BaseConfig):
|
|
70
|
+
spark_llm_gateway_config: Union[
|
|
71
|
+
SparkLLMGatewayObjectConfig[SparkLLMGateway], None
|
|
72
|
+
] = None
|
|
73
|
+
|
|
74
|
+
def update(self, other: "SparkLLMGatewayConfig") -> "SparkLLMGatewayConfig":
|
|
75
|
+
def merge(
|
|
76
|
+
config_a: Union[SparkLLMGatewayObjectConfig, None],
|
|
77
|
+
config_b: Union[SparkLLMGatewayObjectConfig, None],
|
|
78
|
+
) -> Union[SparkLLMGatewayObjectConfig, None]:
|
|
79
|
+
if config_a is not None and config_a.force:
|
|
80
|
+
return config_a
|
|
81
|
+
if config_b:
|
|
82
|
+
return config_b
|
|
83
|
+
return config_a
|
|
84
|
+
|
|
85
|
+
self.spark_llm_gateway_config = merge(
|
|
86
|
+
self.spark_llm_gateway_config, other.spark_llm_gateway_config
|
|
87
|
+
)
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
|
|
55
91
|
# Global LLM Gateway config instance
|
|
56
92
|
llm_gateway_config = LLMGatewayConfig()
|
|
57
93
|
llm_gateway_config.load(default_config_file())
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Global Spark LLM Gateway config instance
|
|
97
|
+
spark_llm_gateway_config = SparkLLMGatewayConfig()
|
|
98
|
+
spark_llm_gateway_config.load(default_config_file())
|
|
@@ -7,6 +7,9 @@ This function demonstrates the new signature-based invocation with Pydantic mode
|
|
|
7
7
|
- Requires Runtime parameter (for agentic capabilities)
|
|
8
8
|
- Type-safe with direct field access (no wrappers)
|
|
9
9
|
- Automatic validation and conversion
|
|
10
|
+
|
|
11
|
+
You can use your AI models configured in Salesforce to generate texts.
|
|
12
|
+
See README.md for how to test locally before deploying to Data Cloud.
|
|
10
13
|
"""
|
|
11
14
|
|
|
12
15
|
import logging
|
|
@@ -12,6 +12,9 @@ Model: YH_Regression_Python_Predicted_SalePrice_CM_12l_ATC937af934
|
|
|
12
12
|
Type: Regression
|
|
13
13
|
Input: Year_Built__c (numeric)
|
|
14
14
|
Output: Predicted_SalePrice
|
|
15
|
+
|
|
16
|
+
You can use your AI models configured in Salesforce to make predictions.
|
|
17
|
+
See README.md for how to test locally before deploying to Data Cloud.
|
|
15
18
|
"""
|
|
16
19
|
|
|
17
20
|
import logging
|
|
@@ -65,13 +65,9 @@ def make_einstein_prediction(runtime: Runtime) -> None:
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def generate_text(runtime: Runtime):
|
|
68
|
+
def generate_text(runtime: Runtime, prompt: str, model: str = "sfdc_ai__DefaultGPT52"):
|
|
69
69
|
builder = GenerateTextRequestBuilder()
|
|
70
|
-
llm_request = (
|
|
71
|
-
builder.set_prompt("Generate 2 dog names")
|
|
72
|
-
.set_model("sfdc_ai__DefaultGPT52")
|
|
73
|
-
.build()
|
|
74
|
-
)
|
|
70
|
+
llm_request = builder.set_prompt(prompt).set_model(model).build()
|
|
75
71
|
llm_response = runtime.llm_gateway.generate_text(llm_request)
|
|
76
72
|
logger.info(
|
|
77
73
|
f"LLM Gateway generate text results - success: [{llm_response.is_success}] "
|
|
@@ -88,13 +84,16 @@ def function(request: dict, runtime: Runtime) -> dict:
|
|
|
88
84
|
current_seq_no = 1 # Start sequence number from 1
|
|
89
85
|
|
|
90
86
|
"""
|
|
91
|
-
You can use your AI models configured in Salesforce
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
You can use your AI models configured in Salesforce to generate texts
|
|
88
|
+
or predict an outcome. See README.md for how to test locally before
|
|
89
|
+
deploying to Data Cloud.
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
|
|
93
|
+
>>> generated_text = generate_text(runtime, "Generate a greeting message")
|
|
94
|
+
... prediction = make_einstein_prediction(runtime)
|
|
95
|
+
|
|
95
96
|
"""
|
|
96
|
-
# generate_text(runtime)
|
|
97
|
-
# make_einstein_prediction(runtime)
|
|
98
97
|
|
|
99
98
|
for item in items:
|
|
100
99
|
# Item is DocElement as dict
|
|
@@ -12,6 +12,32 @@ def main():
|
|
|
12
12
|
# Perform transformations on the DataFrame
|
|
13
13
|
df_upper1 = df.withColumn("description__c", upper(col("description__c")))
|
|
14
14
|
|
|
15
|
+
"""
|
|
16
|
+
You can use your AI models configured in Salesforce to generate column
|
|
17
|
+
values. See README.md for how to test locally before deploying to Data Cloud.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
|
|
21
|
+
>>> from datacustomcode.client import llm_gateway_generate_text_col
|
|
22
|
+
df_generated = df.withColumn(
|
|
23
|
+
... "greeting__c",
|
|
24
|
+
... llm_gateway_generate_text_col(
|
|
25
|
+
... "In one sentence, greet {name} from {city}.",
|
|
26
|
+
... {"name": col("name__c"), "city": col("homecity__c")},
|
|
27
|
+
... model_id="sfdc_ai__DefaultGPT4Omni",
|
|
28
|
+
... ),
|
|
29
|
+
... )
|
|
30
|
+
|
|
31
|
+
You can also invoke the LLM with a literal plain text prompt — no
|
|
32
|
+
``{field}`` substitution is performed on this string.
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
|
|
36
|
+
>>> generated_text = client.llm_gateway_generate_text(
|
|
37
|
+
... prompt, model_id
|
|
38
|
+
... )
|
|
39
|
+
"""
|
|
40
|
+
|
|
15
41
|
# Drop specific columns related to relationships
|
|
16
42
|
df_upper1 = df_upper1.drop("sfdcorganizationid__c")
|
|
17
43
|
df_upper1 = df_upper1.drop("kq_id__c")
|
datacustomcode/token_provider.py
CHANGED
|
@@ -101,83 +101,49 @@ class SFCLITokenProvider(TokenProvider):
|
|
|
101
101
|
|
|
102
102
|
from datacustomcode.deploy import AccessTokenResponse
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
f"'{description}' failed for org '{self.sf_cli_org}': "
|
|
126
|
-
f"{exc.stderr}"
|
|
127
|
-
) from exc
|
|
104
|
+
try:
|
|
105
|
+
result = subprocess.run(
|
|
106
|
+
["sf", "org", "display", "--target-org", self.sf_cli_org, "--json"],
|
|
107
|
+
capture_output=True,
|
|
108
|
+
text=True,
|
|
109
|
+
check=True,
|
|
110
|
+
timeout=30,
|
|
111
|
+
)
|
|
112
|
+
except FileNotFoundError as exc:
|
|
113
|
+
raise RuntimeError(
|
|
114
|
+
"The 'sf' command was not found. "
|
|
115
|
+
"Install Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli"
|
|
116
|
+
) from exc
|
|
117
|
+
except subprocess.TimeoutExpired as exc:
|
|
118
|
+
raise RuntimeError(
|
|
119
|
+
f"'sf org display' timed out for org '{self.sf_cli_org}'"
|
|
120
|
+
) from exc
|
|
121
|
+
except subprocess.CalledProcessError as exc:
|
|
122
|
+
raise RuntimeError(
|
|
123
|
+
f"'sf org display' failed for org '{self.sf_cli_org}': {exc.stderr}"
|
|
124
|
+
) from exc
|
|
128
125
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
try:
|
|
127
|
+
data = json.loads(result.stdout)
|
|
128
|
+
except json.JSONDecodeError as exc:
|
|
129
|
+
raise RuntimeError(
|
|
130
|
+
f"Failed to parse JSON from 'sf org display': {result.stdout}"
|
|
131
|
+
) from exc
|
|
135
132
|
|
|
136
|
-
|
|
137
|
-
raise RuntimeError(
|
|
138
|
-
f"SF CLI error for org '{self.sf_cli_org}': "
|
|
139
|
-
f"{data.get('message', 'unknown error')}"
|
|
140
|
-
)
|
|
141
|
-
return dict(data)
|
|
142
|
-
|
|
143
|
-
# Get org info from sf org display
|
|
144
|
-
display_data = _run_sf_command(
|
|
145
|
-
["sf", "org", "display", "--target-org", self.sf_cli_org, "--json"],
|
|
146
|
-
"sf org display",
|
|
147
|
-
)
|
|
148
|
-
result_data = display_data.get("result", {})
|
|
149
|
-
instance_url = result_data.get("instanceUrl")
|
|
150
|
-
if not instance_url:
|
|
133
|
+
if data.get("status") != 0:
|
|
151
134
|
raise RuntimeError(
|
|
152
|
-
f"
|
|
153
|
-
f"
|
|
135
|
+
f"SF CLI error for org '{self.sf_cli_org}': "
|
|
136
|
+
f"{data.get('message', 'unknown error')}"
|
|
154
137
|
)
|
|
155
138
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
try:
|
|
160
|
-
token_data = _run_sf_command(
|
|
161
|
-
[
|
|
162
|
-
"sf",
|
|
163
|
-
"org",
|
|
164
|
-
"auth",
|
|
165
|
-
"show-access-token",
|
|
166
|
-
"--target-org",
|
|
167
|
-
self.sf_cli_org,
|
|
168
|
-
"--json",
|
|
169
|
-
],
|
|
170
|
-
"sf org auth show-access-token",
|
|
171
|
-
)
|
|
172
|
-
access_token = token_data.get("result", {}).get("accessToken")
|
|
173
|
-
except RuntimeError:
|
|
174
|
-
# Command not available on older SF CLI versions
|
|
175
|
-
access_token = result_data.get("accessToken")
|
|
139
|
+
result_data = data.get("result", {})
|
|
140
|
+
access_token = result_data.get("accessToken")
|
|
141
|
+
instance_url = result_data.get("instanceUrl")
|
|
176
142
|
|
|
177
|
-
if not access_token:
|
|
143
|
+
if not access_token or not instance_url:
|
|
178
144
|
raise RuntimeError(
|
|
179
|
-
f"
|
|
180
|
-
f"
|
|
145
|
+
f"'sf org display' did not return an access token or instance URL "
|
|
146
|
+
f"for org '{self.sf_cli_org}'"
|
|
181
147
|
)
|
|
182
148
|
|
|
183
149
|
return AccessTokenResponse(access_token=access_token, instance_url=instance_url)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: salesforce-data-customcode
|
|
3
|
-
Version: 6.0.
|
|
3
|
+
Version: 6.0.3.dev1
|
|
4
4
|
Summary: Data Cloud Custom Code SDK
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE.txt
|
|
@@ -330,6 +330,52 @@ Options:
|
|
|
330
330
|
- `--function-invoke-opt TEXT`: Currently we support only `UnstructuredChunking` for functions.
|
|
331
331
|
|
|
332
332
|
|
|
333
|
+
## Testing LLM Gateway
|
|
334
|
+
|
|
335
|
+
You can use AI models configured in Salesforce to generate responses while transforming your data. Below is a sample code example:
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
from datacustomcode.client import Client, llm_gateway_generate_text_col
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def main():
|
|
342
|
+
client = Client()
|
|
343
|
+
df = client.read_dlo("Input__dll")
|
|
344
|
+
df_generated = df.withColumn(
|
|
345
|
+
"greeting__c",
|
|
346
|
+
llm_gateway_generate_text_col(
|
|
347
|
+
"In one sentence, greet {name} from {city}.",
|
|
348
|
+
{"name": col("name__c"), "city": col("homecity__c")},
|
|
349
|
+
model_id="sfdc_ai__DefaultGPT4Omni", # An AI model in your org
|
|
350
|
+
),
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
dlo_name = "Output_dll"
|
|
354
|
+
client.write_to_dlo(dlo_name, df_upper1, write_mode=WriteMode.APPEND)
|
|
355
|
+
|
|
356
|
+
greeting = client.llm_gateway_generate_text("In one sentence, generate a greeting message", "sfdc_ai__DefaultGPT52")
|
|
357
|
+
|
|
358
|
+
if __name__ == "__main__":
|
|
359
|
+
main()
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
In order to test this code on your local machine before deploying it to Data Cloud, you must first set up an External Client App that allows access to the Agent API. Follow this guide to create the ECA https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.html#create-a-salesforce-app. You must use `http://localhost:1717/OauthRedirect` as the callback URL.
|
|
363
|
+
|
|
364
|
+
Once the ECA is set up, log in to your org using this ECA
|
|
365
|
+
```
|
|
366
|
+
sf org login web \
|
|
367
|
+
--alias myorg \
|
|
368
|
+
--instance-url https://{MY_DOMAIN_URL} \
|
|
369
|
+
--client-id {CONSUMER_KEY} \
|
|
370
|
+
--scopes "sfap_api api"
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
then you can test your code using `myorg` alias
|
|
374
|
+
```
|
|
375
|
+
datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
|
|
333
379
|
## Docker usage
|
|
334
380
|
|
|
335
381
|
The SDK provides Docker-based development options that allow you to test your code in an environment that closely resembles Data Cloud's execution environment.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
datacustomcode/__init__.py,sha256=
|
|
1
|
+
datacustomcode/__init__.py,sha256=qx-X3U9lU_791ZbAxhGqQeyDw6eqTi9-E9AbYnwJfxU,2071
|
|
2
2
|
datacustomcode/auth.py,sha256=fpSjhIBdv9trC8yq2vuljAix_Euu-4Ah7HDCGhYjOxI,8309
|
|
3
|
-
datacustomcode/cli.py,sha256=
|
|
4
|
-
datacustomcode/client.py,sha256=
|
|
3
|
+
datacustomcode/cli.py,sha256=ObqhOasZSZ8ZNFP6pywV3FpsUOz45_KaZdMNT4BHOKs,13069
|
|
4
|
+
datacustomcode/client.py,sha256=NzPtJkHszRh0GqKUkobPyDUCDauUIaeI-zrac9VR7l8,12813
|
|
5
5
|
datacustomcode/cmd.py,sha256=ZMs46aydJw2EaU26JgCtZmnqESQFHvvaJz10hnjZTBk,3537
|
|
6
6
|
datacustomcode/common_config.py,sha256=SAUnxj3kqmOeWwPmFoYq4tuxokMgURVm4QwcGi-avL4,1928
|
|
7
7
|
datacustomcode/config.py,sha256=2Pk61ieQsEWSxKDxlS66_rliKE8iX0j-9LweEm0aaGo,4072
|
|
8
|
-
datacustomcode/config.yaml,sha256=
|
|
8
|
+
datacustomcode/config.yaml,sha256=Wd8Zd2f1__hRv7166H5IBbU5YoOEOdQNHgAb4ONbFnA,845
|
|
9
9
|
datacustomcode/constants.py,sha256=SskQpUPnQE7LjKh4Z3AdZ2p191_0Kf73jV8gdBXDPLU,1436
|
|
10
10
|
datacustomcode/credentials.py,sha256=D-7Zd3Nh_wStdj8_wUy5cnC8M_mdbfBijhIAi-2EbXs,9467
|
|
11
11
|
datacustomcode/deploy.py,sha256=9yaekNew5ha6bd6rIFERknFROomOeIfikrKXN6jCoq4,18811
|
|
12
12
|
datacustomcode/einstein_platform_client.py,sha256=ON2B_m--vdbCVVMVcLc81T-BRZ5-UuxVCer8E6OEQPA,4083
|
|
13
|
-
datacustomcode/einstein_platform_config.py,sha256=
|
|
13
|
+
datacustomcode/einstein_platform_config.py,sha256=6lb_FRbEzdt5a8-2cR15f13ZKw674uvRJ4Xq0o_pQXE,1490
|
|
14
14
|
datacustomcode/einstein_predictions/__init__.py,sha256=o-iask36phwGA7hGi_sxJpwbITO6h_STDe0J92qD2_M,859
|
|
15
15
|
datacustomcode/einstein_predictions/base.py,sha256=OBV445dpZRtCF5cpdHH49w_6RU_jZY1A-e7VtHTQCFU,1061
|
|
16
16
|
datacustomcode/einstein_predictions/impl/default.py,sha256=fEFhrosozhG0yT87w4Gu8wbe1NgHxBqdAduwWHdWGN4,3011
|
|
17
17
|
datacustomcode/einstein_predictions/types.py,sha256=W7H3sFzm_NdBtnia7O576w0OvM7jwzfGVQmFiZTO8Og,6098
|
|
18
|
-
datacustomcode/einstein_predictions_config.py,sha256=
|
|
18
|
+
datacustomcode/einstein_predictions_config.py,sha256=oxKgp2u7t5SdHVsasBBxsvd3KAfXuZ9uQXTrtpcCUlU,2135
|
|
19
19
|
datacustomcode/file/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
20
20
|
datacustomcode/file/base.py,sha256=2IUlQufPvpHccgyoeZlKhcktO4pS4NKdha03Whq33Zk,745
|
|
21
21
|
datacustomcode/file/path/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
@@ -23,7 +23,7 @@ datacustomcode/file/path/default.py,sha256=jyDv61JUlD5H6lUPAp55_B2toMryKItA8Hu2k
|
|
|
23
23
|
datacustomcode/function/__init__.py,sha256=oag8FevDxbx1vR0tFhtxPd5SvmUEYDj8esRo4v2qu3Q,749
|
|
24
24
|
datacustomcode/function/base.py,sha256=H_i80GcsFScvHJJ6bYLry5phTpsEU1KubpR8D3qnsjo,691
|
|
25
25
|
datacustomcode/function/feature_types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
26
|
-
datacustomcode/function/feature_types/chunking.py,sha256=
|
|
26
|
+
datacustomcode/function/feature_types/chunking.py,sha256=_tCCHj7slD59-aLLEZUFRPOX37q_MEKkL4thi9CNwMw,7180
|
|
27
27
|
datacustomcode/function/runtime.py,sha256=jUduf-pve-0JAv0Lg0HPyLCZ9_Hgcxe25dI7t-DgX9o,3696
|
|
28
28
|
datacustomcode/function_utils.py,sha256=y6vaoSSaJ9CeHhjLCNyqzJT4vx6yCePWRxNLz38ddjQ,12920
|
|
29
29
|
datacustomcode/io/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
@@ -34,23 +34,22 @@ datacustomcode/io/reader/query_api.py,sha256=eVrohrcnTnhSMsGfPRHu5XltjFtGG0hyHt1
|
|
|
34
34
|
datacustomcode/io/reader/sf_cli.py,sha256=x5QacVqRZaZSyph1_wwxo67s8r29wsOcUsOaiF9cDWE,6324
|
|
35
35
|
datacustomcode/io/reader/utils.py,sha256=HlHhPZoHfmWA3mF8kTnd3m4Nd2exaz4NsOJJfQY7Pew,1656
|
|
36
36
|
datacustomcode/io/writer/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
37
|
-
datacustomcode/io/writer/base.py,sha256=
|
|
37
|
+
datacustomcode/io/writer/base.py,sha256=RHafJ-Xmh_TnYcN4QfSh0VdIZeIevKmz9sf05adMgxA,1540
|
|
38
38
|
datacustomcode/io/writer/csv.py,sha256=asty5teBpNQ1fMGHZ7wA3suLhq0sk0lVQPN5x7TOSRk,1555
|
|
39
39
|
datacustomcode/io/writer/print.py,sha256=0g2sP_1Wb95UIyEELWJt3dqM18Iv_CWhDW3mDxcIhns,5105
|
|
40
|
-
datacustomcode/llm_gateway/__init__.py,sha256=
|
|
40
|
+
datacustomcode/llm_gateway/__init__.py,sha256=rcoGpSkv36tZuAOcTxKkhNpM0qV03qgmer_ej07Vmfc,1088
|
|
41
41
|
datacustomcode/llm_gateway/base.py,sha256=CTUhZiZ0JFlmWj6kQpTR4_-mUvqkBKl_Fkdvv9VwxY8,1262
|
|
42
42
|
datacustomcode/llm_gateway/default.py,sha256=QiwrDaUvrh00I-fYYhmogTtqC5r0fmm-JrXxNQLvTc0,1854
|
|
43
|
+
datacustomcode/llm_gateway/errors.py,sha256=ABjztpJwAYMBlmFX808CHHtu4nD6zA4ECelzNJQkJg0,1197
|
|
44
|
+
datacustomcode/llm_gateway/spark_base.py,sha256=apM3FYDPNz3JTgEdlf-7jeryzTYmSzjJsCIt95ZEpvg,1553
|
|
45
|
+
datacustomcode/llm_gateway/spark_default.py,sha256=ctBzkP1vDxgrmoIC6PvfmwxmlPVotkcADK3-M5qyFKI,3794
|
|
43
46
|
datacustomcode/llm_gateway/types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
44
47
|
datacustomcode/llm_gateway/types/generate_text_request.py,sha256=ChxOCzp7St1EYgwl4tWiwfrPyVci4zPyBhnEjWc1Vfs,1448
|
|
45
48
|
datacustomcode/llm_gateway/types/generate_text_request_builder.py,sha256=R4hCgatMPSfWYqaOmeC1IMQj753iDgu7wU992c4tkmk,2565
|
|
46
49
|
datacustomcode/llm_gateway/types/generate_text_response.py,sha256=NSvj6nvzR4cZ0cVs2-PE9Ct3ZY-xL4MQYknJMd_xdDI,1912
|
|
47
50
|
datacustomcode/llm_gateway/types/generate_text_response_builder.py,sha256=6MV6JZuTyHUId3Slw9k7m0KBgjj-5S9HI4qtd94Jl2A,1272
|
|
48
|
-
datacustomcode/llm_gateway_config.py,sha256=
|
|
51
|
+
datacustomcode/llm_gateway_config.py,sha256=ECm9CFqOFOaLHwenvVFAjiRSzG9Eg9fY4pb8nHbQ34c,3312
|
|
49
52
|
datacustomcode/mixin.py,sha256=ZtROqO1W1_D7MV8lw4cw6zzcchJLoZS0aAiXrolYR4k,4914
|
|
50
|
-
datacustomcode/proxy/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
51
|
-
datacustomcode/proxy/base.py,sha256=Gw8of0cBgcOSpjnR7PX8pqWnsjHpt1AgKIK7u6k6DBU,846
|
|
52
|
-
datacustomcode/proxy/client/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
53
|
-
datacustomcode/proxy/client/base.py,sha256=dWFcc5_5vSBxZmo7k5cwKnJl1_gcjvOZYI2EjBUXuaA,1073
|
|
54
53
|
datacustomcode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
54
|
datacustomcode/run.py,sha256=78IpkuEih3GCO6sQPZLFfiKnrCI-eMtEMLsj-1vUvSE,7362
|
|
56
55
|
datacustomcode/scan.py,sha256=Zb9mE733H_xaqyDI-LZjjnIcctMC9j1AaD_kcr9qTh4,14325
|
|
@@ -59,7 +58,7 @@ datacustomcode/spark/base.py,sha256=tlGqM4LxuLoDa7OxJF5nVeb7phO5uvD1DHBQeH7NMMs,
|
|
|
59
58
|
datacustomcode/spark/default.py,sha256=aMB8CaTPYwHbQE_7XqBLQUZPGRdDJcRL72qTVh0aG7M,1433
|
|
60
59
|
datacustomcode/template.py,sha256=FNNi8YPfd-JB-hUt1DDWSFK5AqwKnTnRSy_KpqYluaU,3282
|
|
61
60
|
datacustomcode/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
62
|
-
datacustomcode/templates/function/.devcontainer/devcontainer.json,sha256=
|
|
61
|
+
datacustomcode/templates/function/.devcontainer/devcontainer.json,sha256=lWMFk-SdTKBlQt_VJrMn8gZPmvT4tfcjRpCNhLdElZc,167
|
|
63
62
|
datacustomcode/templates/function/Dockerfile.dependencies,sha256=AfHRddm5l3ujv4vdrf0d-SMB-qxPCOa0XQm6ptP2Euw,174
|
|
64
63
|
datacustomcode/templates/function/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
65
64
|
datacustomcode/templates/function/build_native_dependencies.sh,sha256=dk9vhzlObdsFAO5BtxP7ioOGDBM8JVwJHp_W0712Nlk,222
|
|
@@ -67,17 +66,17 @@ datacustomcode/templates/function/chunking/payload/config.json,sha256=RBNvo1WzZ4
|
|
|
67
66
|
datacustomcode/templates/function/chunking/payload/entrypoint.py,sha256=tzpQJjODulwzLilOoKdOo8GjpdIlCDByjnawpHIQYQA,4517
|
|
68
67
|
datacustomcode/templates/function/chunking/requirements.txt,sha256=Ih0KsVdiTdo7KuIsqFB_AJMRT2r0ao_xDEb3hiDmf48,46
|
|
69
68
|
datacustomcode/templates/function/example/chunking_with_llm/config.json,sha256=EvjuOVssRg2SjcUb5F50RRMGDqag_f69bv8AOflaK1g,38
|
|
70
|
-
datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py,sha256=
|
|
69
|
+
datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py,sha256=6AMVf_busCCDALktG8vkCtjnzJheMgM-OOLML5iLKOg,3437
|
|
71
70
|
datacustomcode/templates/function/example/chunking_with_llm/files/chunking_prompt.txt,sha256=w_gSYNXwZmbMTMjZ_YYwm1IpMsVpI3hyC3ew60zqs_0,446
|
|
72
71
|
datacustomcode/templates/function/example/chunking_with_llm/tests/test.json,sha256=ZcH6QGEWu03dc922Za3vdx6hJY08nfGPie9kkeup-sc,9457
|
|
73
72
|
datacustomcode/templates/function/example/chunking_with_prediction/config.json,sha256=EvjuOVssRg2SjcUb5F50RRMGDqag_f69bv8AOflaK1g,38
|
|
74
|
-
datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py,sha256=
|
|
73
|
+
datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py,sha256=w25_WucA-tUN3O6j-Od_WsW4HDH1Dfp2uJYNfVs_0M4,7722
|
|
75
74
|
datacustomcode/templates/function/example/chunking_with_prediction/tests/test.json,sha256=2EE0c0n-s6eOayb_JrBqeKkXzyxieOyHK3_Mbm--Nmo,1073
|
|
76
75
|
datacustomcode/templates/function/payload/config.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
|
|
77
|
-
datacustomcode/templates/function/payload/entrypoint.py,sha256=
|
|
76
|
+
datacustomcode/templates/function/payload/entrypoint.py,sha256=uWb9mT7GaOvVWBK8P7vHS1GNbNaH--rSLV8J1v0eTHY,5667
|
|
78
77
|
datacustomcode/templates/function/requirements-dev.txt,sha256=qT2-m2FOgiYPTvqaNy0yRzIAXqHgR5b8stccYXsXVi8,88
|
|
79
78
|
datacustomcode/templates/function/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
|
|
80
|
-
datacustomcode/templates/script/.devcontainer/devcontainer.json,sha256=
|
|
79
|
+
datacustomcode/templates/script/.devcontainer/devcontainer.json,sha256=lWMFk-SdTKBlQt_VJrMn8gZPmvT4tfcjRpCNhLdElZc,167
|
|
81
80
|
datacustomcode/templates/script/Dockerfile,sha256=l8HEy5X7BsW9Gi7rBYM6G2czwk-1832RRIos7xyFzpI,463
|
|
82
81
|
datacustomcode/templates/script/Dockerfile.dependencies,sha256=vBbTfgcBkVQVCnrJZE_QEx89ddTQrLZGeyVTZXU8TI8,206
|
|
83
82
|
datacustomcode/templates/script/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -87,13 +86,13 @@ datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv,sh
|
|
|
87
86
|
datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py,sha256=Mfm3iQtEHTQRW6cmZTwRKdTh3IeGWR-teXrd6x-YLSY,2223
|
|
88
87
|
datacustomcode/templates/script/jupyterlab.sh,sha256=IHR3YQ8d_busuyvesByhJgzCKULIFPI-Hqogs0NPhCs,2432
|
|
89
88
|
datacustomcode/templates/script/payload/config.json,sha256=0d2mEMt4NHIeOUTsgiPMuRKdOLIQxmh-Wq-IfEqU-gc,28
|
|
90
|
-
datacustomcode/templates/script/payload/entrypoint.py,sha256=
|
|
89
|
+
datacustomcode/templates/script/payload/entrypoint.py,sha256=Ox2guNka3r0GW2jzKsmH7AP70j1-1Qqr_jhtH5dkPOM,1590
|
|
91
90
|
datacustomcode/templates/script/requirements-dev.txt,sha256=OWwuy1awesqOZOS3Zizmdd6BDnSePpGFN5bq5IrALvc,176
|
|
92
91
|
datacustomcode/templates/script/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
|
|
93
|
-
datacustomcode/token_provider.py,sha256=
|
|
92
|
+
datacustomcode/token_provider.py,sha256=KPj_ca6mcBmhXHaPmZjAI4it8QvOWdwKJL8yfqxfYwU,5446
|
|
94
93
|
datacustomcode/version.py,sha256=9LlbVrzwBvut1L308QbwNBgxdQk5CrghH39JARVSxms,989
|
|
95
|
-
salesforce_data_customcode-6.0.
|
|
96
|
-
salesforce_data_customcode-6.0.
|
|
97
|
-
salesforce_data_customcode-6.0.
|
|
98
|
-
salesforce_data_customcode-6.0.
|
|
99
|
-
salesforce_data_customcode-6.0.
|
|
94
|
+
salesforce_data_customcode-6.0.3.dev1.dist-info/METADATA,sha256=wmHyC6LrpV7uYwKuMBQEwfrztUX9gLb7v7YRwsYYGAg,21724
|
|
95
|
+
salesforce_data_customcode-6.0.3.dev1.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
96
|
+
salesforce_data_customcode-6.0.3.dev1.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
|
|
97
|
+
salesforce_data_customcode-6.0.3.dev1.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
|
|
98
|
+
salesforce_data_customcode-6.0.3.dev1.dist-info/RECORD,,
|
datacustomcode/proxy/__init__.py
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
-
# SPDX-License-Identifier: Apache-2
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
-
# SPDX-License-Identifier: Apache-2
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
-
# SPDX-License-Identifier: Apache-2
|
|
3
|
-
#
|
|
4
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
-
# you may not use this file except in compliance with the License.
|
|
6
|
-
# You may obtain a copy of the License at
|
|
7
|
-
#
|
|
8
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
-
#
|
|
10
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
-
# See the License for the specific language governing permissions and
|
|
14
|
-
# limitations under the License.
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
from abc import abstractmethod
|
|
18
|
-
|
|
19
|
-
from datacustomcode.proxy.base import BaseProxyAccessLayer
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class BaseProxyClient(BaseProxyAccessLayer):
|
|
23
|
-
def __init__(self):
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
|
-
@abstractmethod
|
|
27
|
-
def call_llm_gateway(self, llmModelId: str, prompt: str, maxTokens: int) -> str: ...
|
|
28
|
-
|
|
29
|
-
@abstractmethod
|
|
30
|
-
def llm_gateway_generate_text(
|
|
31
|
-
self, template, values, llmModelId: str, maxTokens: int
|
|
32
|
-
): ...
|
{salesforce_data_customcode-6.0.2.dist-info → salesforce_data_customcode-6.0.3.dev1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|