venice-cli 0.36.0__tar.gz → 0.37.0__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.
- {venice_cli-0.36.0 → venice_cli-0.37.0}/PKG-INFO +4 -2
- {venice_cli-0.36.0 → venice_cli-0.37.0}/README.md +3 -1
- venice_cli-0.37.0/src/venice/__init__.py +1 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_agent.py +16 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_code.py +5 -4
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_mcp.py +25 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_chat.py +6 -4
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_code.py +3 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_mcp_tools.py +31 -0
- venice_cli-0.36.0/src/venice/__init__.py +0 -1
- {venice_cli-0.36.0 → venice_cli-0.37.0}/.gitignore +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/CONTRIBUTING.md +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/LICENSE +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/Makefile +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/SECURITY.md +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/bin/venice +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/install.sh +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/pyproject.toml +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/__main__.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/audio_player.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/audio_post.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/auth.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/billing.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/cli.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/client.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/__init__.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_audio.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_index.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_mcp_client.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_models.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_openai.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_queue.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_repl.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/_shared.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/balance.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/bg_remove.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/chat.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/code.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/config.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/contact_sheet.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/embed.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/image.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/image_edit.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/index.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/login.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/master.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/mcp_serve.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/models.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/music.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/search.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/sfx.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/tts.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/upscale.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/commands/video.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/config.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/image_montage.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/mcp_server.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/src/venice/userconfig.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/__init__.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/_mcp_fake_server.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_agent.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_auth.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_balance.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_bg_remove.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_client.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_code_command.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_config.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_contact_sheet.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_embed.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_image.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_image_edit.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_index.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_master.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_mcp_client.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_mcp_serve.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_models.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_music.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_repl.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_search.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_sfx.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_shared.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_shared_openai.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_tts.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_upscale.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/tests/test_video.py +0 -0
- {venice_cli-0.36.0 → venice_cli-0.37.0}/uninstall.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: venice-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.37.0
|
|
4
4
|
Summary: A stdlib-only Python CLI for the Venice.ai API: audio, video, images, chat, and embeddings.
|
|
5
5
|
Project-URL: Homepage, https://github.com/gobha-me/venice-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/gobha-me/venice-cli
|
|
@@ -630,7 +630,9 @@ a read-only [semantic search](#semantic-search) over the project's local
|
|
|
630
630
|
`venice_models`, a read-only lookup that lists model ids for a given catalog
|
|
631
631
|
type (its single `type` arg — text/code/image/video/music/tts/embedding/upscale,
|
|
632
632
|
or `all`) so the model can pick a valid `model` for the other tools instead of
|
|
633
|
-
guessing
|
|
633
|
+
guessing, and `venice_model_details` (single `model` arg) which returns one
|
|
634
|
+
model's pricing (cost), input context/prompt-length limits, and capabilities so
|
|
635
|
+
the agent can budget its input. (`venice code` gets both too.)
|
|
634
636
|
|
|
635
637
|
```sh
|
|
636
638
|
# One command, multiple steps: the model generates an image, then critiques it.
|
|
@@ -592,7 +592,9 @@ a read-only [semantic search](#semantic-search) over the project's local
|
|
|
592
592
|
`venice_models`, a read-only lookup that lists model ids for a given catalog
|
|
593
593
|
type (its single `type` arg — text/code/image/video/music/tts/embedding/upscale,
|
|
594
594
|
or `all`) so the model can pick a valid `model` for the other tools instead of
|
|
595
|
-
guessing
|
|
595
|
+
guessing, and `venice_model_details` (single `model` arg) which returns one
|
|
596
|
+
model's pricing (cost), input context/prompt-length limits, and capabilities so
|
|
597
|
+
the agent can budget its input. (`venice code` gets both too.)
|
|
596
598
|
|
|
597
599
|
```sh
|
|
598
600
|
# One command, multiple steps: the model generates an image, then critiques it.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.37.0"
|
|
@@ -198,6 +198,13 @@ _MODELS_SCHEMA = _obj(
|
|
|
198
198
|
required=["type"],
|
|
199
199
|
)
|
|
200
200
|
|
|
201
|
+
_MODEL_DETAILS_SCHEMA = _obj(
|
|
202
|
+
{
|
|
203
|
+
"model": _p("string", "The model id to describe (e.g. from venice_models)."),
|
|
204
|
+
},
|
|
205
|
+
required=["model"],
|
|
206
|
+
)
|
|
207
|
+
|
|
201
208
|
# Schema for a tool folded in ONLY via `only=` (e.g. `venice code --assets`), so it
|
|
202
209
|
# is not part of chat's default advertised set. Curated subset of
|
|
203
210
|
# `_mcp.image_edit_tool`; `confirm`/`max_spend`/`output_dir` omitted (loop-injected).
|
|
@@ -308,6 +315,15 @@ _BUILTINS = [
|
|
|
308
315
|
_MODELS_SCHEMA,
|
|
309
316
|
False,
|
|
310
317
|
),
|
|
318
|
+
(
|
|
319
|
+
"venice_model_details",
|
|
320
|
+
"model_details_tool",
|
|
321
|
+
"Get one model's details -- pricing (cost), input context/prompt-length "
|
|
322
|
+
"limits (your input budget), and capabilities -- so you can budget input "
|
|
323
|
+
"and confirm a model fits before using it. Read-only; not spend-gated.",
|
|
324
|
+
_MODEL_DETAILS_SCHEMA,
|
|
325
|
+
False,
|
|
326
|
+
),
|
|
311
327
|
(
|
|
312
328
|
"project_search",
|
|
313
329
|
"search_tool",
|
|
@@ -528,11 +528,12 @@ def code_tools(
|
|
|
528
528
|
_SEARCH_SCHEMA, search_invoke, paid=False,
|
|
529
529
|
))
|
|
530
530
|
|
|
531
|
-
#
|
|
532
|
-
# asset tools instead of guessing (
|
|
531
|
+
# Free model-catalog lookups so the agent can pick a valid `model` for the
|
|
532
|
+
# asset tools (and see cost/context limits) instead of guessing (need a client
|
|
533
|
+
# for the /models GET).
|
|
533
534
|
if client is not None:
|
|
534
|
-
tools.extend(_agent.builtin_tools(
|
|
535
|
-
|
|
535
|
+
tools.extend(_agent.builtin_tools(
|
|
536
|
+
client, only={"venice_models", "venice_model_details"}, config=config))
|
|
536
537
|
|
|
537
538
|
if assets and client is not None:
|
|
538
539
|
asset_dir = os.environ.get("VENICE_MCP_OUTPUT_DIR") or root
|
|
@@ -781,3 +781,28 @@ def models_tool(client, *, type: str) -> dict:
|
|
|
781
781
|
"models": by_type}
|
|
782
782
|
return {"status": "ok", "type": type,
|
|
783
783
|
"count": len(by_type[type]), "models": by_type[type]}
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
def model_details_tool(client, *, model: str) -> dict:
|
|
787
|
+
"""Details for one model id: pricing (cost), context/prompt-length limits, and
|
|
788
|
+
capabilities -- so an agent can budget its input and confirm a model fits
|
|
789
|
+
before using it. Read-only; not spend-gated. May scan the catalog by type to
|
|
790
|
+
locate the id.
|
|
791
|
+
"""
|
|
792
|
+
if not model or not str(model).strip():
|
|
793
|
+
return _err("models: a model id is required")
|
|
794
|
+
m = _models_cmd._find_model(client, str(model).strip())
|
|
795
|
+
if m is None:
|
|
796
|
+
return _err(f"models: no model with id {model!r}")
|
|
797
|
+
spec = m.get("model_spec") if isinstance(m.get("model_spec"), dict) else {}
|
|
798
|
+
return {
|
|
799
|
+
"status": "ok",
|
|
800
|
+
"id": m.get("id"),
|
|
801
|
+
"type": m.get("type"),
|
|
802
|
+
"name": spec.get("name") or m.get("name"),
|
|
803
|
+
"pricing": spec.get("pricing"),
|
|
804
|
+
"available_context_tokens": spec.get("availableContextTokens"),
|
|
805
|
+
"prompt_character_limit": spec.get("promptCharacterLimit"),
|
|
806
|
+
"capabilities": spec.get("capabilities"),
|
|
807
|
+
"traits": spec.get("traits"),
|
|
808
|
+
}
|
|
@@ -505,9 +505,10 @@ class TestChatAgent(unittest.TestCase):
|
|
|
505
505
|
f"{t['function']['name']} leaks control kwarg {banned}",
|
|
506
506
|
)
|
|
507
507
|
names = {t["function"]["name"] for t in tools}
|
|
508
|
-
self.assertEqual(len(names),
|
|
508
|
+
self.assertEqual(len(names), 10) # media/chat + project_search + models(+details)
|
|
509
509
|
self.assertIn("project_search", names)
|
|
510
510
|
self.assertIn("venice_models", names)
|
|
511
|
+
self.assertIn("venice_model_details", names)
|
|
511
512
|
|
|
512
513
|
def test_tool_error_surfaced_not_fatal(self):
|
|
513
514
|
seq = [
|
|
@@ -637,7 +638,7 @@ class TestChatMcp(unittest.TestCase):
|
|
|
637
638
|
names = self._tool_names(calls[0])
|
|
638
639
|
self.assertIn("fs__read", names) # remote tool advertised
|
|
639
640
|
self.assertIn("venice_image", names) # alongside the built-ins
|
|
640
|
-
self.assertEqual(len(names),
|
|
641
|
+
self.assertEqual(len(names), 11) # 10 built-ins + 1 remote
|
|
641
642
|
self.assertEqual(attach.specs, [("fs", {"command": "srv", "args": []})])
|
|
642
643
|
tool_msgs = [m for m in calls[1]["messages"] if m.get("role") == "tool"]
|
|
643
644
|
self.assertIn("127.0.0.1", tool_msgs[0]["content"])
|
|
@@ -651,7 +652,7 @@ class TestChatMcp(unittest.TestCase):
|
|
|
651
652
|
)
|
|
652
653
|
self.assertEqual(rc, 0)
|
|
653
654
|
attach.assert_not_called()
|
|
654
|
-
self.assertEqual(len(self._tool_names(calls[0])),
|
|
655
|
+
self.assertEqual(len(self._tool_names(calls[0])), 10) # built-ins only
|
|
655
656
|
|
|
656
657
|
def test_unknown_mcp_server_exits_2_before_model(self):
|
|
657
658
|
attach = mock.MagicMock()
|
|
@@ -739,8 +740,9 @@ class TestBuiltinToolsRegistry(unittest.TestCase):
|
|
|
739
740
|
# chat's default advertisement must not grow when code gains asset tools
|
|
740
741
|
from venice.commands import _agent
|
|
741
742
|
names = {t.name for t in _agent.builtin_tools(object())}
|
|
742
|
-
self.assertEqual(len(names),
|
|
743
|
+
self.assertEqual(len(names), 10) # +venice_models +venice_model_details (free)
|
|
743
744
|
self.assertIn("venice_models", names)
|
|
745
|
+
self.assertIn("venice_model_details", names)
|
|
744
746
|
self.assertNotIn("venice_image_edit", names)
|
|
745
747
|
|
|
746
748
|
def test_only_can_select_code_asset_extra(self):
|
|
@@ -249,11 +249,14 @@ class TestCodeFactory(unittest.TestCase):
|
|
|
249
249
|
def test_models_tool_present_with_client(self):
|
|
250
250
|
by = {t.name: t for t in _code.code_tools("/tmp", client=object())}
|
|
251
251
|
self.assertIn("venice_models", by) # free model-catalog lookup for the agent
|
|
252
|
+
self.assertIn("venice_model_details", by) # cost/context-limit lookup
|
|
252
253
|
self.assertFalse(by["venice_models"].paid) # read-only, not spend-gated
|
|
254
|
+
self.assertFalse(by["venice_model_details"].paid)
|
|
253
255
|
|
|
254
256
|
def test_models_tool_absent_without_client(self):
|
|
255
257
|
names = {t.name for t in _code.code_tools("/tmp")}
|
|
256
258
|
self.assertNotIn("venice_models", names) # needs a client for the /models GET
|
|
259
|
+
self.assertNotIn("venice_model_details", names)
|
|
257
260
|
|
|
258
261
|
def test_asset_tools_are_paid(self):
|
|
259
262
|
by = {t.name: t for t in _code.code_tools("/tmp", client=object(),
|
|
@@ -526,5 +526,36 @@ class TestModelsTool(_ToolTest):
|
|
|
526
526
|
self.assertIn("unknown type", out["message"])
|
|
527
527
|
|
|
528
528
|
|
|
529
|
+
class TestModelDetailsTool(_ToolTest):
|
|
530
|
+
def test_returns_curated_details(self):
|
|
531
|
+
# `text` is first in MODEL_TYPES, so _find_model matches on the first GET.
|
|
532
|
+
spec = {"name": "Big", "pricing": {"input": {"usd": 1.5}},
|
|
533
|
+
"availableContextTokens": 131072, "promptCharacterLimit": 1500,
|
|
534
|
+
"capabilities": {"supportsFunctionCalling": True},
|
|
535
|
+
"traits": ["default"]}
|
|
536
|
+
catalog = json.dumps(
|
|
537
|
+
{"data": [{"id": "big-model", "type": "text", "model_spec": spec}]}
|
|
538
|
+
).encode()
|
|
539
|
+
with mock.patch("venice.client.urllib.request.urlopen",
|
|
540
|
+
_seq(FakeResp(200, catalog))), self.stdout_guard():
|
|
541
|
+
out = _mcp.model_details_tool(_client(), model="big-model")
|
|
542
|
+
self.assertEqual(out["status"], "ok")
|
|
543
|
+
self.assertEqual(out["id"], "big-model")
|
|
544
|
+
self.assertEqual(out["available_context_tokens"], 131072)
|
|
545
|
+
self.assertEqual(out["prompt_character_limit"], 1500)
|
|
546
|
+
self.assertEqual(out["pricing"], {"input": {"usd": 1.5}})
|
|
547
|
+
self.assertTrue(out["capabilities"]["supportsFunctionCalling"])
|
|
548
|
+
|
|
549
|
+
def test_unknown_model_errors(self):
|
|
550
|
+
from venice.commands.models import MODEL_TYPES
|
|
551
|
+
empty = json.dumps({"data": []}).encode()
|
|
552
|
+
resps = _seq(*[FakeResp(200, empty) for _ in MODEL_TYPES])
|
|
553
|
+
with mock.patch("venice.client.urllib.request.urlopen", resps), \
|
|
554
|
+
self.stdout_guard():
|
|
555
|
+
out = _mcp.model_details_tool(_client(), model="nope")
|
|
556
|
+
self.assertEqual(out["status"], "error")
|
|
557
|
+
self.assertIn("no model", out["message"])
|
|
558
|
+
|
|
559
|
+
|
|
529
560
|
if __name__ == "__main__":
|
|
530
561
|
unittest.main()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.36.0"
|
|
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
|
|
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
|