discolike-cli 0.6.1__tar.gz → 0.6.2__tar.gz
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.
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/PKG-INFO +3 -2
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/pyproject.toml +3 -2
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/providers.py +51 -6
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_discogen_cli.py +4 -1
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_providers_cli.py +65 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/.gitignore +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/LICENSE +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/README.md +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/__init__.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/_help.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/_inputs.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/_loopback.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/_output.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/account.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/auth.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/bulk.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/company.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/contacts.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/discogen.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/discover.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/email.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/enrich.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/main.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/match.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/prospecting.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/py.typed +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/queries.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/src/discolike_cli/signup.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/conftest.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_account.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_auth.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_auth_oauth.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_bulk_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_company.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_contacts_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_discover.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_email_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_enrich_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_entrypoint.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_file_inputs_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_help.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_inputs.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_match_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_output.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_prospecting_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_queries_cli.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_sdk_parity.py +0 -0
- {discolike_cli-0.6.1 → discolike_cli-0.6.2}/tests/test_signup_cli.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: discolike-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Official CLI for the DiscoLike API
|
|
5
5
|
Project-URL: Homepage, https://www.discolike.com
|
|
6
6
|
Project-URL: Documentation, https://docs.discolike.com
|
|
@@ -21,10 +21,11 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: 3.13
|
|
23
23
|
Classifier: Programming Language :: Python :: 3.14
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
24
25
|
Classifier: Topic :: Utilities
|
|
25
26
|
Classifier: Typing :: Typed
|
|
26
27
|
Requires-Python: >=3.11
|
|
27
|
-
Requires-Dist: discolike==0.6.
|
|
28
|
+
Requires-Dist: discolike==0.6.2
|
|
28
29
|
Requires-Dist: rich>=13.0
|
|
29
30
|
Requires-Dist: typer<0.28,>=0.26.1
|
|
30
31
|
Description-Content-Type: text/markdown
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "discolike-cli"
|
|
7
|
-
version = "0.6.
|
|
7
|
+
version = "0.6.2"
|
|
8
8
|
description = "Official CLI for the DiscoLike API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -12,7 +12,7 @@ license-files = ["LICENSE"]
|
|
|
12
12
|
requires-python = ">=3.11"
|
|
13
13
|
authors = [{ name = "DiscoLike", email = "support@discolike.com" }]
|
|
14
14
|
dependencies = [
|
|
15
|
-
"discolike==0.6.
|
|
15
|
+
"discolike==0.6.2",
|
|
16
16
|
"typer>=0.26.1,<0.28",
|
|
17
17
|
"rich>=13.0",
|
|
18
18
|
]
|
|
@@ -25,6 +25,7 @@ classifiers = [
|
|
|
25
25
|
"Programming Language :: Python :: 3.12",
|
|
26
26
|
"Programming Language :: Python :: 3.13",
|
|
27
27
|
"Programming Language :: Python :: 3.14",
|
|
28
|
+
"Programming Language :: Python :: 3.15",
|
|
28
29
|
"Programming Language :: Python :: 3 :: Only",
|
|
29
30
|
"Operating System :: OS Independent",
|
|
30
31
|
"Environment :: Console",
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from urllib.parse import parse_qsl
|
|
4
|
+
from urllib.parse import urlencode
|
|
5
|
+
|
|
3
6
|
import typer
|
|
4
7
|
|
|
5
8
|
from discolike.requests import LLMProviderCreateRequest
|
|
@@ -15,6 +18,23 @@ FORMAT_HELP = "Output format: json or table (table auto-selected on a TTY; falls
|
|
|
15
18
|
search_providers_app = typer.Typer(help="Manage BYOK web search provider integrations (Tavily, Serper, etc.).")
|
|
16
19
|
llm_providers_app = typer.Typer(help="Manage BYOK LLM provider integrations (OpenAI, Anthropic, custom endpoints).")
|
|
17
20
|
|
|
21
|
+
LLM_PROVIDER_HELP = "LLM provider key, e.g. openai, anthropic, bedrock, snowflake, watsonx, or custom."
|
|
22
|
+
REGION_HELP = (
|
|
23
|
+
"Provider region: an AWS region for bedrock and bedrock_mantle, a watsonx region (us-south, eu-de, ...) "
|
|
24
|
+
"for watsonx. `discogen models` lists them under provider_regions."
|
|
25
|
+
)
|
|
26
|
+
ACCOUNT_HELP = "Snowflake account identifier, e.g. orgname-accountname (snowflake only)."
|
|
27
|
+
PROJECT_HELP = "watsonx project ID (watsonx only)."
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _with_model_settings(model_name: str, *, region: str | None, account: str | None, project: str | None) -> str:
|
|
31
|
+
"""The API reads provider settings from model_name after "#", e.g. "<model>#region=us-east-1"."""
|
|
32
|
+
flags = {key: value for key, value in (("region", region), ("account", account), ("project", project)) if value}
|
|
33
|
+
if not flags:
|
|
34
|
+
return model_name
|
|
35
|
+
base, _, existing = model_name.partition("#")
|
|
36
|
+
return f"{base}#{urlencode(dict(parse_qsl(existing)) | flags)}"
|
|
37
|
+
|
|
18
38
|
|
|
19
39
|
@search_providers_app.command("list")
|
|
20
40
|
@handle_errors
|
|
@@ -149,10 +169,13 @@ def llm_list_command(
|
|
|
149
169
|
def llm_create_command(
|
|
150
170
|
ctx: typer.Context,
|
|
151
171
|
name: str = typer.Option(..., "--name", help="User-friendly name for the integration."),
|
|
152
|
-
provider: str = typer.Option(..., "--provider", help=
|
|
172
|
+
provider: str = typer.Option(..., "--provider", help=LLM_PROVIDER_HELP),
|
|
153
173
|
api_key: str = typer.Option(..., "--api-key", help="API key for the provider."),
|
|
154
174
|
model_name: str = typer.Option(..., "--model-name", help="Default model name for this integration."),
|
|
155
175
|
base_url: str | None = typer.Option(None, "--base-url", help="Endpoint URL (required for the custom provider)."),
|
|
176
|
+
region: str | None = typer.Option(None, "--region", help=REGION_HELP),
|
|
177
|
+
account: str | None = typer.Option(None, "--account", help=ACCOUNT_HELP),
|
|
178
|
+
project: str | None = typer.Option(None, "--project", help=PROJECT_HELP),
|
|
156
179
|
) -> None:
|
|
157
180
|
"""Create an LLM provider integration."""
|
|
158
181
|
from discolike_cli.main import get_client
|
|
@@ -160,7 +183,12 @@ def llm_create_command(
|
|
|
160
183
|
request = build_request(
|
|
161
184
|
LLMProviderCreateRequest,
|
|
162
185
|
_merge_params(
|
|
163
|
-
None,
|
|
186
|
+
None,
|
|
187
|
+
integration_name=name,
|
|
188
|
+
provider=provider,
|
|
189
|
+
api_key=api_key,
|
|
190
|
+
model_name=_with_model_settings(model_name, region=region, account=account, project=project),
|
|
191
|
+
base_url=base_url,
|
|
164
192
|
),
|
|
165
193
|
)
|
|
166
194
|
emit(get_client(ctx).llm_providers.create(request))
|
|
@@ -185,10 +213,13 @@ def llm_update_command(
|
|
|
185
213
|
ctx: typer.Context,
|
|
186
214
|
integration_id: str = typer.Argument(..., help="ID of the LLM provider integration to update."),
|
|
187
215
|
name: str = typer.Option(..., "--name", help="User-friendly name for the integration."),
|
|
188
|
-
provider: str = typer.Option(..., "--provider", help=
|
|
216
|
+
provider: str = typer.Option(..., "--provider", help=LLM_PROVIDER_HELP),
|
|
189
217
|
model_name: str = typer.Option(..., "--model-name", help="Default model name for this integration."),
|
|
190
218
|
api_key: str | None = typer.Option(None, "--api-key", help="New API key (omit to keep the stored key)."),
|
|
191
219
|
base_url: str | None = typer.Option(None, "--base-url", help="Endpoint URL (required for the custom provider)."),
|
|
220
|
+
region: str | None = typer.Option(None, "--region", help=REGION_HELP),
|
|
221
|
+
account: str | None = typer.Option(None, "--account", help=ACCOUNT_HELP),
|
|
222
|
+
project: str | None = typer.Option(None, "--project", help=PROJECT_HELP),
|
|
192
223
|
) -> None:
|
|
193
224
|
"""Update an LLM provider integration."""
|
|
194
225
|
from discolike_cli.main import get_client
|
|
@@ -196,7 +227,13 @@ def llm_update_command(
|
|
|
196
227
|
request = build_request(
|
|
197
228
|
LLMProviderUpdateRequest,
|
|
198
229
|
{
|
|
199
|
-
**_merge_params(
|
|
230
|
+
**_merge_params(
|
|
231
|
+
None,
|
|
232
|
+
integration_name=name,
|
|
233
|
+
provider=provider,
|
|
234
|
+
model_name=_with_model_settings(model_name, region=region, account=account, project=project),
|
|
235
|
+
base_url=base_url,
|
|
236
|
+
),
|
|
200
237
|
"api_key": api_key,
|
|
201
238
|
},
|
|
202
239
|
)
|
|
@@ -233,10 +270,13 @@ def llm_set_default_command(
|
|
|
233
270
|
def llm_test_connection_command(
|
|
234
271
|
ctx: typer.Context,
|
|
235
272
|
name: str = typer.Option("cli-test", "--name", help="Name to label the test configuration."),
|
|
236
|
-
provider: str = typer.Option(..., "--provider", help=
|
|
273
|
+
provider: str = typer.Option(..., "--provider", help=LLM_PROVIDER_HELP),
|
|
237
274
|
api_key: str = typer.Option(..., "--api-key", help="API key for the provider."),
|
|
238
275
|
model_name: str = typer.Option(..., "--model-name", help="Model name to test against."),
|
|
239
276
|
base_url: str | None = typer.Option(None, "--base-url", help="Endpoint URL (required for the custom provider)."),
|
|
277
|
+
region: str | None = typer.Option(None, "--region", help=REGION_HELP),
|
|
278
|
+
account: str | None = typer.Option(None, "--account", help=ACCOUNT_HELP),
|
|
279
|
+
project: str | None = typer.Option(None, "--project", help=PROJECT_HELP),
|
|
240
280
|
) -> None:
|
|
241
281
|
"""Test a provider configuration before saving it."""
|
|
242
282
|
from discolike_cli.main import get_client
|
|
@@ -244,7 +284,12 @@ def llm_test_connection_command(
|
|
|
244
284
|
request = build_request(
|
|
245
285
|
LLMProviderCreateRequest,
|
|
246
286
|
_merge_params(
|
|
247
|
-
None,
|
|
287
|
+
None,
|
|
288
|
+
integration_name=name,
|
|
289
|
+
provider=provider,
|
|
290
|
+
api_key=api_key,
|
|
291
|
+
model_name=_with_model_settings(model_name, region=region, account=account, project=project),
|
|
292
|
+
base_url=base_url,
|
|
248
293
|
),
|
|
249
294
|
)
|
|
250
295
|
emit(get_client(ctx).llm_providers.test_connection(request))
|
|
@@ -314,7 +314,10 @@ def test_discogen_models_hits_models_endpoint(install_build_client: Callable[[Ha
|
|
|
314
314
|
install_build_client(handler)
|
|
315
315
|
result = runner.invoke(app, ["discogen", "models"])
|
|
316
316
|
assert result.exit_code == 0, result.output
|
|
317
|
-
assert json.loads(result.stdout) == {
|
|
317
|
+
assert json.loads(result.stdout) == {
|
|
318
|
+
"models": {"openai": [{"name": "gpt-5.4", "supports_web_search": False}]},
|
|
319
|
+
"provider_regions": {},
|
|
320
|
+
}
|
|
318
321
|
|
|
319
322
|
|
|
320
323
|
def test_discogen_status_default_family_discogen(install_build_client: Callable[[Handler], None]) -> None:
|
|
@@ -138,6 +138,71 @@ def test_llm_providers_create_posts_json(install_build_client: Callable[[Handler
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
|
|
141
|
+
def test_llm_providers_create_appends_provider_settings_to_model_name(
|
|
142
|
+
install_build_client: Callable[[Handler], None],
|
|
143
|
+
) -> None:
|
|
144
|
+
captured: dict[str, dict[str, str]] = {}
|
|
145
|
+
|
|
146
|
+
def handler(request: httpx2.Request) -> httpx2.Response:
|
|
147
|
+
captured["body"] = json.loads(request.content)
|
|
148
|
+
return httpx2.Response(200, json={"message": "created", "integration_id": "llm1"})
|
|
149
|
+
|
|
150
|
+
install_build_client(handler)
|
|
151
|
+
result = runner.invoke(
|
|
152
|
+
app,
|
|
153
|
+
[
|
|
154
|
+
"llm-providers",
|
|
155
|
+
"create",
|
|
156
|
+
"--name",
|
|
157
|
+
"watsonx",
|
|
158
|
+
"--provider",
|
|
159
|
+
"watsonx",
|
|
160
|
+
"--api-key",
|
|
161
|
+
"ibm-key",
|
|
162
|
+
"--model-name",
|
|
163
|
+
"watsonx/ibm/granite-3-8b-instruct",
|
|
164
|
+
"--region",
|
|
165
|
+
"eu-de",
|
|
166
|
+
"--project",
|
|
167
|
+
"11111111-2222-3333-4444-555555555555",
|
|
168
|
+
],
|
|
169
|
+
)
|
|
170
|
+
assert result.exit_code == 0, result.output
|
|
171
|
+
assert captured["body"]["model_name"] == (
|
|
172
|
+
"watsonx/ibm/granite-3-8b-instruct#region=eu-de&project=11111111-2222-3333-4444-555555555555"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def test_llm_providers_update_flags_override_an_existing_settings_suffix(
|
|
177
|
+
install_build_client: Callable[[Handler], None],
|
|
178
|
+
) -> None:
|
|
179
|
+
captured: dict[str, dict[str, str]] = {}
|
|
180
|
+
|
|
181
|
+
def handler(request: httpx2.Request) -> httpx2.Response:
|
|
182
|
+
captured["body"] = json.loads(request.content)
|
|
183
|
+
return httpx2.Response(200, json={"message": "updated"})
|
|
184
|
+
|
|
185
|
+
install_build_client(handler)
|
|
186
|
+
result = runner.invoke(
|
|
187
|
+
app,
|
|
188
|
+
[
|
|
189
|
+
"llm-providers",
|
|
190
|
+
"update",
|
|
191
|
+
"llm1",
|
|
192
|
+
"--name",
|
|
193
|
+
"watsonx",
|
|
194
|
+
"--provider",
|
|
195
|
+
"watsonx",
|
|
196
|
+
"--model-name",
|
|
197
|
+
"watsonx/ibm/granite-3-8b-instruct#region=us-south&project=p1",
|
|
198
|
+
"--region",
|
|
199
|
+
"eu-de",
|
|
200
|
+
],
|
|
201
|
+
)
|
|
202
|
+
assert result.exit_code == 0, result.output
|
|
203
|
+
assert captured["body"]["model_name"] == "watsonx/ibm/granite-3-8b-instruct#region=eu-de&project=p1"
|
|
204
|
+
|
|
205
|
+
|
|
141
206
|
def test_llm_providers_update_keeps_null_api_key(install_build_client: Callable[[Handler], None]) -> None:
|
|
142
207
|
captured: dict[str, object] = {}
|
|
143
208
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|