salesforce-data-customcode 6.0.0.dev1__py3-none-any.whl → 6.0.1__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/cli.py +14 -10
- datacustomcode/einstein_platform_client.py +27 -4
- datacustomcode/einstein_predictions/impl/default.py +1 -1
- datacustomcode/llm_gateway/default.py +1 -1
- datacustomcode/token_provider.py +63 -36
- {salesforce_data_customcode-6.0.0.dev1.dist-info → salesforce_data_customcode-6.0.1.dist-info}/METADATA +7 -1
- {salesforce_data_customcode-6.0.0.dev1.dist-info → salesforce_data_customcode-6.0.1.dist-info}/RECORD +10 -10
- {salesforce_data_customcode-6.0.0.dev1.dist-info → salesforce_data_customcode-6.0.1.dist-info}/WHEEL +0 -0
- {salesforce_data_customcode-6.0.0.dev1.dist-info → salesforce_data_customcode-6.0.1.dist-info}/entry_points.txt +0 -0
- {salesforce_data_customcode-6.0.0.dev1.dist-info → salesforce_data_customcode-6.0.1.dist-info}/licenses/LICENSE.txt +0 -0
datacustomcode/cli.py
CHANGED
|
@@ -198,6 +198,11 @@ 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(
|
|
202
|
+
"--use-in-feature",
|
|
203
|
+
default="SearchIndexChunking",
|
|
204
|
+
help="Feature where this function will be used.",
|
|
205
|
+
)
|
|
201
206
|
def deploy(
|
|
202
207
|
path: str,
|
|
203
208
|
name: str,
|
|
@@ -207,6 +212,7 @@ def deploy(
|
|
|
207
212
|
profile: str,
|
|
208
213
|
network: str,
|
|
209
214
|
sf_cli_org: Optional[str],
|
|
215
|
+
use_in_feature: Optional[str],
|
|
210
216
|
):
|
|
211
217
|
from datacustomcode.constants import USE_IN_FEATURE_MAPPING_FOR_CONNECT_API
|
|
212
218
|
from datacustomcode.deploy import (
|
|
@@ -242,20 +248,18 @@ def deploy(
|
|
|
242
248
|
)
|
|
243
249
|
|
|
244
250
|
if package_type == "function":
|
|
245
|
-
#
|
|
251
|
+
# Try to infer use_in_feature from function signature; fall back to
|
|
252
|
+
# the explicit flag value (defaults to SearchIndexChunking)
|
|
246
253
|
entrypoint_path = os.path.join(path, ENTRYPOINT_FILE)
|
|
247
|
-
|
|
248
|
-
if
|
|
254
|
+
inferred = infer_use_in_feature(entrypoint_path)
|
|
255
|
+
if inferred:
|
|
256
|
+
use_in_feature = inferred
|
|
249
257
|
logger.info(f"Inferred use_in_feature: {use_in_feature}")
|
|
250
258
|
else:
|
|
251
|
-
|
|
252
|
-
"Error: Could not infer function invoke options. "
|
|
253
|
-
"Please provide --use-in-feature",
|
|
254
|
-
fg="red",
|
|
255
|
-
)
|
|
256
|
-
raise click.Abort()
|
|
259
|
+
logger.info(f"Using use_in_feature: {use_in_feature}")
|
|
257
260
|
|
|
258
|
-
|
|
261
|
+
assert use_in_feature is not None
|
|
262
|
+
# Map feature names to Connect API names
|
|
259
263
|
mapped_feature = USE_IN_FEATURE_MAPPING_FOR_CONNECT_API.get(
|
|
260
264
|
use_in_feature, use_in_feature
|
|
261
265
|
)
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# See the License for the specific language governing permissions and
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
|
+
import os
|
|
16
17
|
from typing import (
|
|
17
18
|
Any,
|
|
18
19
|
Dict,
|
|
@@ -30,10 +31,6 @@ from datacustomcode.token_provider import (
|
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
class EinsteinPlatformClient:
|
|
33
|
-
EINSTEIN_PLATFORM_MODELS_URL = (
|
|
34
|
-
"https://api.salesforce.com/einstein/platform/v1/models"
|
|
35
|
-
)
|
|
36
|
-
|
|
37
34
|
def __init__(
|
|
38
35
|
self,
|
|
39
36
|
credentials_profile: Optional[str] = None,
|
|
@@ -48,8 +45,34 @@ class EinsteinPlatformClient:
|
|
|
48
45
|
self._token_provider = CredentialsTokenProvider(profile)
|
|
49
46
|
logger.debug(f"Using credentials token provider with profile: {profile}")
|
|
50
47
|
self.token_response = None
|
|
48
|
+
self._einstein_url_cache: Optional[str] = None
|
|
51
49
|
super().__init__(**kwargs)
|
|
52
50
|
|
|
51
|
+
def _get_einstein_platform_url(self) -> str:
|
|
52
|
+
if self._einstein_url_cache is not None:
|
|
53
|
+
return self._einstein_url_cache
|
|
54
|
+
|
|
55
|
+
env = os.environ.get("SFDC_EINSTEIN_API_ENV", "prod").lower()
|
|
56
|
+
if env not in ("dev", "test", "stage", "prod"):
|
|
57
|
+
logger.warning(
|
|
58
|
+
f"Unknown SFDC_EINSTEIN_API_ENV value '{env}', defaulting to prod"
|
|
59
|
+
)
|
|
60
|
+
env = "prod"
|
|
61
|
+
|
|
62
|
+
base_url = self._get_base_url_for_env(env)
|
|
63
|
+
logger.info(f"Using Einstein Platform API endpoint: {base_url} (env={env})")
|
|
64
|
+
self._einstein_url_cache = f"{base_url}/einstein/platform/v1/models"
|
|
65
|
+
return self._einstein_url_cache
|
|
66
|
+
|
|
67
|
+
def _get_base_url_for_env(self, env: str) -> str:
|
|
68
|
+
env_map = {
|
|
69
|
+
"dev": "https://dev.api.salesforce.com",
|
|
70
|
+
"test": "https://test.api.salesforce.com",
|
|
71
|
+
"stage": "https://stage.api.salesforce.com",
|
|
72
|
+
"prod": "https://api.salesforce.com",
|
|
73
|
+
}
|
|
74
|
+
return env_map.get(env, "https://api.salesforce.com")
|
|
75
|
+
|
|
53
76
|
def _get_headers(self):
|
|
54
77
|
if self.token_response is None:
|
|
55
78
|
self.token_response = self._token_provider.get_token()
|
|
@@ -48,7 +48,7 @@ class DefaultEinsteinPredictions(EinsteinPlatformClient, EinsteinPredictions):
|
|
|
48
48
|
)
|
|
49
49
|
|
|
50
50
|
api_url = (
|
|
51
|
-
f"{self.
|
|
51
|
+
f"{self._get_einstein_platform_url()}/{request.model_api_name}/{endpoint}"
|
|
52
52
|
)
|
|
53
53
|
|
|
54
54
|
prediction_columns: List[Dict[str, Any]] = []
|
|
@@ -29,7 +29,7 @@ class DefaultLLMGateway(EinsteinPlatformClient, LLMGateway):
|
|
|
29
29
|
|
|
30
30
|
def generate_text(self, request: GenerateTextRequest) -> GenerateTextResponse:
|
|
31
31
|
api_url = (
|
|
32
|
-
f"{self.
|
|
32
|
+
f"{self._get_einstein_platform_url()}/{request.model_name}/generations"
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
payload: Dict[str, Any] = {"prompt": request.prompt}
|
datacustomcode/token_provider.py
CHANGED
|
@@ -101,48 +101,75 @@ 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
|
-
|
|
104
|
+
def _run_sf_command(args: list[str], description: str) -> dict:
|
|
105
|
+
try:
|
|
106
|
+
result = subprocess.run(
|
|
107
|
+
args,
|
|
108
|
+
capture_output=True,
|
|
109
|
+
text=True,
|
|
110
|
+
check=True,
|
|
111
|
+
timeout=30,
|
|
112
|
+
)
|
|
113
|
+
except FileNotFoundError as exc:
|
|
114
|
+
raise RuntimeError(
|
|
115
|
+
"The 'sf' command was not found. "
|
|
116
|
+
"Install Salesforce CLI: "
|
|
117
|
+
"https://developer.salesforce.com/tools/salesforcecli"
|
|
118
|
+
) from exc
|
|
119
|
+
except subprocess.TimeoutExpired as exc:
|
|
120
|
+
raise RuntimeError(
|
|
121
|
+
f"'{description}' timed out for org '{self.sf_cli_org}'"
|
|
122
|
+
) from exc
|
|
123
|
+
except subprocess.CalledProcessError as exc:
|
|
124
|
+
raise RuntimeError(
|
|
125
|
+
f"'{description}' failed for org '{self.sf_cli_org}': "
|
|
126
|
+
f"{exc.stderr}"
|
|
127
|
+
) from exc
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
try:
|
|
130
|
+
data = json.loads(result.stdout)
|
|
131
|
+
except json.JSONDecodeError as exc:
|
|
132
|
+
raise RuntimeError(
|
|
133
|
+
f"Failed to parse JSON from '{description}': {result.stdout}"
|
|
134
|
+
) from exc
|
|
132
135
|
|
|
133
|
-
|
|
136
|
+
if data.get("status") != 0:
|
|
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 instanceUrl 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
|
+
instance_url = display_data.get("result", {}).get("instanceUrl")
|
|
149
|
+
if not instance_url:
|
|
134
150
|
raise RuntimeError(
|
|
135
|
-
f"
|
|
136
|
-
f"
|
|
151
|
+
f"'sf org display' did not return an instance URL "
|
|
152
|
+
f"for org '{self.sf_cli_org}'"
|
|
137
153
|
)
|
|
138
154
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
# Get access token via show-access-token (newer SF CLI versions
|
|
156
|
+
# redact the token in sf org display)
|
|
157
|
+
token_data = _run_sf_command(
|
|
158
|
+
[
|
|
159
|
+
"sf",
|
|
160
|
+
"org",
|
|
161
|
+
"auth",
|
|
162
|
+
"show-access-token",
|
|
163
|
+
"--target-org",
|
|
164
|
+
self.sf_cli_org,
|
|
165
|
+
"--json",
|
|
166
|
+
],
|
|
167
|
+
"sf org auth show-access-token",
|
|
168
|
+
)
|
|
169
|
+
access_token = token_data.get("result", {}).get("accessToken")
|
|
170
|
+
if not access_token:
|
|
144
171
|
raise RuntimeError(
|
|
145
|
-
f"'sf org
|
|
172
|
+
f"'sf org auth show-access-token' did not return an access token "
|
|
146
173
|
f"for org '{self.sf_cli_org}'"
|
|
147
174
|
)
|
|
148
175
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: salesforce-data-customcode
|
|
3
|
-
Version: 6.0.
|
|
3
|
+
Version: 6.0.1
|
|
4
4
|
Summary: Data Cloud Custom Code SDK
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE.txt
|
|
@@ -254,12 +254,18 @@ Instead of using `datacustomcode configure`, you can also set credentials via en
|
|
|
254
254
|
| `SFDC_REFRESH_TOKEN` | OAuth refresh token |
|
|
255
255
|
| `SFDC_ACCESS_TOKEN` | (Optional) OAuth core/access token |
|
|
256
256
|
|
|
257
|
+
**Einstein Platform API Environment (Optional):**
|
|
258
|
+
| Variable | Description |
|
|
259
|
+
|----------|-------------|
|
|
260
|
+
| `SFDC_EINSTEIN_API_ENV` | Einstein Platform API environment: `dev`, `test`, `stage`, or `prod`. If not set, automatically inferred from login URL. Set this explicitly if auto-detection fails. |
|
|
261
|
+
|
|
257
262
|
Example usage:
|
|
258
263
|
```bash
|
|
259
264
|
export SFDC_LOGIN_URL="https://login.salesforce.com"
|
|
260
265
|
export SFDC_CLIENT_ID="your_client_id"
|
|
261
266
|
export SFDC_CLIENT_SECRET="your_client_secret"
|
|
262
267
|
export SFDC_REFRESH_TOKEN="your_refresh_token"
|
|
268
|
+
export SFDC_EINSTEIN_API_ENV="test" # optional
|
|
263
269
|
|
|
264
270
|
datacustomcode run ./payload/entrypoint.py
|
|
265
271
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
datacustomcode/__init__.py,sha256=Fj2pIYQqLV_kQrMywrYPj0NsMtHjx4tkvwyqSt-m0E0,1530
|
|
2
2
|
datacustomcode/auth.py,sha256=fpSjhIBdv9trC8yq2vuljAix_Euu-4Ah7HDCGhYjOxI,8309
|
|
3
|
-
datacustomcode/cli.py,sha256=
|
|
3
|
+
datacustomcode/cli.py,sha256=tAtSSUMoVQtME_y1fxpNq4Lw1vfQsP1a6UxlEPiV9Sw,13237
|
|
4
4
|
datacustomcode/client.py,sha256=TO9TkIsJjCEMlQMnD-NBGF26fk2K9jpOZjOT_XWKJ0g,9340
|
|
5
5
|
datacustomcode/cmd.py,sha256=ZMs46aydJw2EaU26JgCtZmnqESQFHvvaJz10hnjZTBk,3537
|
|
6
6
|
datacustomcode/common_config.py,sha256=SAUnxj3kqmOeWwPmFoYq4tuxokMgURVm4QwcGi-avL4,1928
|
|
@@ -9,11 +9,11 @@ datacustomcode/config.yaml,sha256=iMs3HPMLHwnesJ9KRD0-CpJqtHRehQvq2w2od9uE0aU,77
|
|
|
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
|
-
datacustomcode/einstein_platform_client.py,sha256=
|
|
12
|
+
datacustomcode/einstein_platform_client.py,sha256=ON2B_m--vdbCVVMVcLc81T-BRZ5-UuxVCer8E6OEQPA,4083
|
|
13
13
|
datacustomcode/einstein_platform_config.py,sha256=EYnAKz0z1hNN9A8GHtaYm-Ek4GqUi68iYrJ1TSR-J9w,1416
|
|
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
|
-
datacustomcode/einstein_predictions/impl/default.py,sha256=
|
|
16
|
+
datacustomcode/einstein_predictions/impl/default.py,sha256=fEFhrosozhG0yT87w4Gu8wbe1NgHxBqdAduwWHdWGN4,3011
|
|
17
17
|
datacustomcode/einstein_predictions/types.py,sha256=W7H3sFzm_NdBtnia7O576w0OvM7jwzfGVQmFiZTO8Og,6098
|
|
18
18
|
datacustomcode/einstein_predictions_config.py,sha256=dwY3Q5MFBHm60lL27m-Srt5BpcURc_PuKpaW-ALOqw4,2131
|
|
19
19
|
datacustomcode/file/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
@@ -39,7 +39,7 @@ datacustomcode/io/writer/csv.py,sha256=asty5teBpNQ1fMGHZ7wA3suLhq0sk0lVQPN5x7TOS
|
|
|
39
39
|
datacustomcode/io/writer/print.py,sha256=0g2sP_1Wb95UIyEELWJt3dqM18Iv_CWhDW3mDxcIhns,5105
|
|
40
40
|
datacustomcode/llm_gateway/__init__.py,sha256=xT7J9qZByD80WWk-835JcJSvQx8_NiX6qsBPhq7mU6k,800
|
|
41
41
|
datacustomcode/llm_gateway/base.py,sha256=CTUhZiZ0JFlmWj6kQpTR4_-mUvqkBKl_Fkdvv9VwxY8,1262
|
|
42
|
-
datacustomcode/llm_gateway/default.py,sha256=
|
|
42
|
+
datacustomcode/llm_gateway/default.py,sha256=QiwrDaUvrh00I-fYYhmogTtqC5r0fmm-JrXxNQLvTc0,1854
|
|
43
43
|
datacustomcode/llm_gateway/types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
44
44
|
datacustomcode/llm_gateway/types/generate_text_request.py,sha256=ChxOCzp7St1EYgwl4tWiwfrPyVci4zPyBhnEjWc1Vfs,1448
|
|
45
45
|
datacustomcode/llm_gateway/types/generate_text_request_builder.py,sha256=R4hCgatMPSfWYqaOmeC1IMQj753iDgu7wU992c4tkmk,2565
|
|
@@ -90,10 +90,10 @@ datacustomcode/templates/script/payload/config.json,sha256=0d2mEMt4NHIeOUTsgiPMu
|
|
|
90
90
|
datacustomcode/templates/script/payload/entrypoint.py,sha256=qpFA-jkhaYYF2CFNQ7_7MZVefU7SxnoMQIQYi7ox2dY,691
|
|
91
91
|
datacustomcode/templates/script/requirements-dev.txt,sha256=OWwuy1awesqOZOS3Zizmdd6BDnSePpGFN5bq5IrALvc,176
|
|
92
92
|
datacustomcode/templates/script/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
|
|
93
|
-
datacustomcode/token_provider.py,sha256=
|
|
93
|
+
datacustomcode/token_provider.py,sha256=a16r5xYeCOPR3M3JKvEV7JVIG7DOzDswObRBI33MQOk,6461
|
|
94
94
|
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.
|
|
95
|
+
salesforce_data_customcode-6.0.1.dist-info/METADATA,sha256=PVoEUlTf9pjQlJq8Yi3Mt7migPd0K16ORl80T2gsMbc,20162
|
|
96
|
+
salesforce_data_customcode-6.0.1.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
97
|
+
salesforce_data_customcode-6.0.1.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
|
|
98
|
+
salesforce_data_customcode-6.0.1.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
|
|
99
|
+
salesforce_data_customcode-6.0.1.dist-info/RECORD,,
|
{salesforce_data_customcode-6.0.0.dev1.dist-info → salesforce_data_customcode-6.0.1.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|