venice-cli 0.83.0__tar.gz → 0.83.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.
- {venice_cli-0.83.0 → venice_cli-0.83.2}/PKG-INFO +22 -56
- {venice_cli-0.83.0 → venice_cli-0.83.2}/README.md +21 -55
- venice_cli-0.83.2/src/venice/__init__.py +1 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/client.py +6 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_agent.py +8 -62
- venice_cli-0.83.2/src/venice/commands/_browser.py +29 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_code.py +8 -10
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_exec.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_index.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_mailbox.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_mcp.py +4 -68
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_memory.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_repl.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_session.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_steer.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/chat.py +17 -14
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/code.py +15 -15
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/memory.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/secret.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/sessions.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/userconfig.py +6 -9
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/_drive.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/_venice_fake_server.py +2 -2
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_agent.py +10 -28
- venice_cli-0.83.2/tests/test_browser.py +51 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_chat.py +17 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_client.py +109 -2
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_code.py +4 -15
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_code_command.py +17 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_drive_cli.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_fake_server.py +1 -1
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_mcp_tools.py +14 -62
- venice_cli-0.83.0/src/venice/__init__.py +0 -1
- venice_cli-0.83.0/src/venice/commands/_browser.py +0 -386
- venice_cli-0.83.0/tests/test_browser.py +0 -287
- {venice_cli-0.83.0 → venice_cli-0.83.2}/.gitignore +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/CONTRIBUTING.md +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/LICENSE +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/Makefile +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/SECURITY.md +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/bin/venice +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/install.sh +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/pyproject.toml +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/__main__.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/audio_player.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/audio_post.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/auth.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/billing.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/cli.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/__init__.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_audio.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_compact.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_mcp_client.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_models.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_openai.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_persona.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_queue.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_review.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/_shared.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/balance.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/bg_remove.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/completion.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/config.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/contact_sheet.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/embed.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/image.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/image_edit.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/index.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/login.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/master.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/mcp_serve.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/models.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/music.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/review.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/search.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/sfx.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/tts.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/upscale.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/commands/video.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/config.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/image_montage.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/src/venice/mcp_server.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/__init__.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/_hygiene.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/_mcp_fake_server.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_auth.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_balance.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_bg_remove.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_cli.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_compact.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_completion.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_config.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_contact_sheet.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_embed.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_exec.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_image.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_image_edit.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_index.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_login.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_mailbox.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_master.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_mcp_client.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_mcp_serve.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_memory.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_models.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_music.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_persona.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_planner.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_profiles.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_repl.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_review.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_search.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_secret.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_sessions.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_sfx.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_shared.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_shared_openai.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_source_hygiene.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_spawn.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_steer.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_tts.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_upscale.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_video.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/tests/test_web_search.py +0 -0
- {venice_cli-0.83.0 → venice_cli-0.83.2}/uninstall.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: venice-cli
|
|
3
|
-
Version: 0.83.
|
|
3
|
+
Version: 0.83.2
|
|
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
|
|
@@ -905,9 +905,9 @@ Details and safety:
|
|
|
905
905
|
| `--shell-allow CMD` | allow only these commands for `--shell` (repeatable; adds to config `shell.allow`) |
|
|
906
906
|
| `--shell-deny PATTERN` | refuse commands matching these globs (repeatable; adds to config `shell.deny`) |
|
|
907
907
|
| `--shell-unrestricted` | acknowledge an empty allowlist under `--yes` (required for that combination) |
|
|
908
|
-
| `--browser` |
|
|
909
|
-
| `--browser-allow HOST` |
|
|
910
|
-
| `--browser-deny PATTERN` |
|
|
908
|
+
| `--browser` | reserved; temporarily exits 2 without network access while the browser rail is security-disabled |
|
|
909
|
+
| `--browser-allow HOST` | retained browser-policy config for compatibility; inert while `--browser` is disabled |
|
|
910
|
+
| `--browser-deny PATTERN` | retained browser-policy config for compatibility; inert while `--browser` is disabled |
|
|
911
911
|
| `--memory` | add persistent memory + task tools (durable notes + a checklist); implies `--tools` (see [Memory & tasks](#memory--tasks---memory)) |
|
|
912
912
|
| `--mcp NAME` | attach a registered external MCP server's tools (repeatable) |
|
|
913
913
|
| `--no-mcp` | attach no MCP servers (overrides a configured default) |
|
|
@@ -948,66 +948,32 @@ venice config set shell.allow '["git", "gh", "ls", "cat"]'
|
|
|
948
948
|
|
|
949
949
|
#### Web & browser tools (`--browser`)
|
|
950
950
|
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
raw HTML (`mode=html`). Zero extra dependencies; good for non-JS "read this page."
|
|
957
|
-
- **`browser_capture`** — headless-renders the page with a **Chromium-family browser**
|
|
958
|
-
(`chromium`/`chrome`/`brave`) and returns the **post-JS DOM** (`mode=dom`/`text`) and/or
|
|
959
|
-
a **screenshot PNG** (`mode=screenshot`/`both`, written to `--output` and returned as a
|
|
960
|
-
path, never inline). Pass `assert_contains="…"` to deterministically check the rendered
|
|
961
|
-
DOM contains a string — the robust "did the JS actually appear" check (beats eyeballing a
|
|
962
|
-
screenshot). If only **Firefox** is installed it degrades to screenshot-only (its
|
|
963
|
-
headless CLI can't dump the DOM); with no browser at all it reports "no headless browser
|
|
964
|
-
available," like the `git` rail.
|
|
951
|
+
`web_fetch` and `browser_capture` are temporarily unavailable while
|
|
952
|
+
[GHSA-mqjr-2vh8-6fvg](https://github.com/sirkitree/venice/security/advisories/GHSA-mqjr-2vh8-6fvg)
|
|
953
|
+
is contained. In v0.83.2, passing `--browser` exits with status 2 before loading the SDK,
|
|
954
|
+
credentials, or any network client. The direct implementation seams also return an error,
|
|
955
|
+
and the agent does not advertise either tool.
|
|
965
956
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
```
|
|
971
|
-
|
|
972
|
-
**URL safety.** The scheme must be `http`/`https` and the cloud-metadata endpoint
|
|
973
|
-
(`169.254.169.254`) is **always** blocked — these hard stops are not configurable. `file://`
|
|
974
|
-
and everything non-http is refused. On top of that, an operator **allow/deny** policy (CLI
|
|
975
|
-
flags add to a shared top-level `browser` section in [config](#config)) scopes which hosts
|
|
976
|
-
are reachable:
|
|
977
|
-
|
|
978
|
-
```sh
|
|
979
|
-
venice config set browser.deny '["*.internal", "10.*"]'
|
|
980
|
-
venice config set browser.allow '["localhost", "*.example.com"]'
|
|
981
|
-
```
|
|
982
|
-
|
|
983
|
-
- **Deny** globs match the URL host and the full URL, are always enforced, and win over
|
|
984
|
-
allow. A non-empty **allow** list restricts to matching hosts; empty = any host (still
|
|
985
|
-
subject to the hard stops + deny). `localhost` is reachable by default (the common case is
|
|
986
|
-
verifying a locally-served page).
|
|
987
|
-
- The headless browser runs untrusted page JS under an **allowlisted environment** (the
|
|
988
|
-
Venice API key and other ambient tokens are dropped) and a throwaway profile dir.
|
|
989
|
-
- DOM/text output and downloads are size-capped; tune with `defaults.browser.*`
|
|
990
|
-
(`wait_ms`, `timeout`, `max_bytes`).
|
|
991
|
-
- **Not exposed over `venice mcp-serve`** in this release (chat/code only), like
|
|
992
|
-
`project_search`/`reindex`.
|
|
957
|
+
The `--browser-allow`, `--browser-deny`, and `browser.*` config keys remain accepted only
|
|
958
|
+
to preserve existing configuration. They do not enable network access. Restoring this rail
|
|
959
|
+
requires an enforced egress boundary that covers redirects, DNS rebinding, browser
|
|
960
|
+
subresources, and page scripts—not another URL-only filter.
|
|
993
961
|
|
|
994
962
|
#### Web search (`--web-search`)
|
|
995
963
|
|
|
996
|
-
`--
|
|
997
|
-
other half of the loop — **discovery**. It adds one tool, `venice_web_search`, so the coding
|
|
964
|
+
`--web-search` adds one discovery tool, `venice_web_search`, so the coding
|
|
998
965
|
agent can look something up on the web when a fix needs documentation it doesn't have a link
|
|
999
966
|
for (an API's docs, a library's usage, an error message).
|
|
1000
967
|
|
|
1001
968
|
`venice_web_search(query)` makes **one** Venice web-search completion (server-side
|
|
1002
969
|
`enable_web_search` + `enable_web_citations`, the same feature behind `venice chat
|
|
1003
970
|
--web-search`) and returns a short **answer** plus the **cited URLs**. To then read a cited
|
|
1004
|
-
page in full,
|
|
1005
|
-
|
|
1006
|
-
browser policy still governs what gets read.**
|
|
971
|
+
page in full, open it outside Venice: the direct `web_fetch` follow-up rail is temporarily
|
|
972
|
+
disabled as described above.
|
|
1007
973
|
|
|
1008
974
|
```sh
|
|
1009
|
-
# discover
|
|
1010
|
-
venice code --web-search --
|
|
975
|
+
# discover: search returns an answer and its cited URLs
|
|
976
|
+
venice code --web-search --auto \
|
|
1011
977
|
"The stripe SDK call is failing with an idempotency error — look up the fix and apply it."
|
|
1012
978
|
```
|
|
1013
979
|
|
|
@@ -1060,7 +1026,7 @@ venice memory tasks # the project checklist (--status filters)
|
|
|
1060
1026
|
- **Locations:** project notes/tasks at `<root>/.venice/memory/` (git-ignored by default,
|
|
1061
1027
|
like the semantic index); global notes at `~/.config/venice/memory/`
|
|
1062
1028
|
(`$VENICE_MEMORY_DIR` overrides). All store files are `0600`.
|
|
1063
|
-
- **Hygiene (
|
|
1029
|
+
- **Hygiene (AGENTS.md):** a note **name** is refused if it's secret-shaped
|
|
1064
1030
|
(`credentials`, `id_rsa*`, `*.key`, `.env`, `*secrets*`, …), so the store can't be used
|
|
1065
1031
|
to label or stash a credential.
|
|
1066
1032
|
- **Not exposed over `venice mcp-serve`** (chat/code only), like the browser rails.
|
|
@@ -1465,7 +1431,7 @@ jq '.usage.billed_total' ~/.config/venice/sessions/<id>.json
|
|
|
1465
1431
|
| `run` | run a shell command (`/bin/sh -c`) at the **active** root | yes |
|
|
1466
1432
|
| `attach_root` | register another directory as a project root (for work spanning repos) and, by default, switch the active root into it so relative paths and `run`/`git` follow — writes outside the writable roots fail loudly | no |
|
|
1467
1433
|
| `venice_image` / `venice_image_edit` / `venice_sfx` / `venice_music` / `venice_tts` / `venice_upscale` / `venice_bg_remove` / `venice_video` | generate/edit images, audio & video into the project — **opt-in with `--assets`** | yes |
|
|
1468
|
-
| `web_fetch` / `browser_capture` |
|
|
1434
|
+
| `web_fetch` / `browser_capture` | temporarily unavailable for security; not advertised to the agent (see [Web & browser tools](#web--browser-tools---browser)) | no |
|
|
1469
1435
|
| `memory_write` / `memory_read` / `memory_search` / `memory_list` | durable notes the agent recalls across turns/sessions (two tiers: project + global) — **opt-in with `--memory`** (see [Memory & tasks](#memory--tasks---memory)) | no |
|
|
1470
1436
|
| `task_add` / `task_update` / `task_list` | a project-only checklist the agent tracks (`pending`/`in_progress`/`done`) — **opt-in with `--memory`** | no |
|
|
1471
1437
|
| `venice_scout` | delegate a read-only investigation to a disposable subagent with a fresh context; returns a structured report so exploration doesn't pollute the main context — **opt-in with `--scout`** (see [Scout subagent](#scout-subagent---scout)) | no |
|
|
@@ -1503,7 +1469,7 @@ it unrestricted (unchanged behavior).
|
|
|
1503
1469
|
| `--max-tool-calls N` | cap tool invocations before forcing a final answer (default 25) |
|
|
1504
1470
|
| `--exec-timeout SECS` | timeout for `run`/`git` (default 120) |
|
|
1505
1471
|
| `--shell-allow CMD` / `--shell-deny PATTERN` | scope the `run` tool with the shared allow/deny policy (repeatable; adds to config `shell.*`) |
|
|
1506
|
-
| `--browser` / `--browser-allow HOST` / `--browser-deny PATTERN` |
|
|
1472
|
+
| `--browser` / `--browser-allow HOST` / `--browser-deny PATTERN` | compatibility flags for the security-disabled browser rail; `--browser` exits 2 without network access (see [Web & browser tools](#web--browser-tools---browser)) |
|
|
1507
1473
|
| `--assets` | also expose the in-process asset-generation tools (image / image-edit / sfx / music / tts / upscale / bg-remove / video) so the agent can create images, audio & video in the project; paid — each confirms per call unless `--auto` |
|
|
1508
1474
|
| `--scout` | expose `venice_scout`: delegate a read-only investigation to a disposable subagent with a fresh context; keeps exploration out of the main context (see [Scout subagent](#scout-subagent---scout)) |
|
|
1509
1475
|
| `--spawn` | expose `venice_spawn`: delegate a bounded **write/paid** task to a disposable **worker** subagent with a fresh context and a role-scoped subset of your tools; edit churn stays quarantined and it returns a structured report to merge (see [Worker subagent](#worker-subagent---spawn)) |
|
|
@@ -1511,7 +1477,7 @@ it unrestricted (unchanged behavior).
|
|
|
1511
1477
|
| `--subagent-max-tokens N` | per-subagent cap on the cumulative prompt+completion **tokens** a `venice_scout` **or** `venice_spawn` subagent spends across its turns (default **off**; `<= 0` disables); once crossed the subagent is asked to wrap up and its report carries the token count. A cumulative-usage ceiling, **not** a context-window size limit, and distinct from `--max-tokens` (per-turn output); config `defaults.code.subagent_max_tokens` |
|
|
1512
1478
|
| `--planner` | planner harness: implies `--scout --spawn --memory`, mandates the decompose → dispatch → track → **merge** protocol, and adds `venice_merge` — a consolidated rollup of every dispatch (see [Planner harness](#planner-harness---planner)) |
|
|
1513
1479
|
| `--parallel` | dispatch **independent** `venice_scout`/`venice_spawn` subagents **concurrently** (bounded pool) instead of one at a time, so a planner's independent units overlap in wall-clock; opt-in, serial otherwise; config `defaults.code.parallel` (see [Parallel dispatch](#parallel-dispatch---parallel)) |
|
|
1514
|
-
| `--web-search` / `--web-search-model MODEL` | expose `venice_web_search` so the agent can **discover** documentation on the web (answer + cited URLs
|
|
1480
|
+
| `--web-search` / `--web-search-model MODEL` | expose `venice_web_search` so the agent can **discover** documentation on the web (answer + cited URLs; see [Web search](#web-search---web-search)) |
|
|
1515
1481
|
| `--review` | expose `venice_review`: hand the current diff to a **cold-context reviewer** (fresh context, read-only tools, a different model where one exists) and fix what it reports before handing work back. Capped at **3 reviews per session**. Findings only — a review is not a merge gate (see [Reviewer rail](#reviewer-rail---review)) |
|
|
1516
1482
|
| `--review-model MODEL` | model for `--review` (default: a function-calling model from a **different family** than the coding model; falls back to the coding model with a warning); config `defaults.code.review_model` |
|
|
1517
1483
|
| `--review-rounds N` | passes `venice_review` makes over the same diff (default **1**, max 3); config `defaults.code.review_rounds` |
|
|
@@ -865,9 +865,9 @@ Details and safety:
|
|
|
865
865
|
| `--shell-allow CMD` | allow only these commands for `--shell` (repeatable; adds to config `shell.allow`) |
|
|
866
866
|
| `--shell-deny PATTERN` | refuse commands matching these globs (repeatable; adds to config `shell.deny`) |
|
|
867
867
|
| `--shell-unrestricted` | acknowledge an empty allowlist under `--yes` (required for that combination) |
|
|
868
|
-
| `--browser` |
|
|
869
|
-
| `--browser-allow HOST` |
|
|
870
|
-
| `--browser-deny PATTERN` |
|
|
868
|
+
| `--browser` | reserved; temporarily exits 2 without network access while the browser rail is security-disabled |
|
|
869
|
+
| `--browser-allow HOST` | retained browser-policy config for compatibility; inert while `--browser` is disabled |
|
|
870
|
+
| `--browser-deny PATTERN` | retained browser-policy config for compatibility; inert while `--browser` is disabled |
|
|
871
871
|
| `--memory` | add persistent memory + task tools (durable notes + a checklist); implies `--tools` (see [Memory & tasks](#memory--tasks---memory)) |
|
|
872
872
|
| `--mcp NAME` | attach a registered external MCP server's tools (repeatable) |
|
|
873
873
|
| `--no-mcp` | attach no MCP servers (overrides a configured default) |
|
|
@@ -908,66 +908,32 @@ venice config set shell.allow '["git", "gh", "ls", "cat"]'
|
|
|
908
908
|
|
|
909
909
|
#### Web & browser tools (`--browser`)
|
|
910
910
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
raw HTML (`mode=html`). Zero extra dependencies; good for non-JS "read this page."
|
|
917
|
-
- **`browser_capture`** — headless-renders the page with a **Chromium-family browser**
|
|
918
|
-
(`chromium`/`chrome`/`brave`) and returns the **post-JS DOM** (`mode=dom`/`text`) and/or
|
|
919
|
-
a **screenshot PNG** (`mode=screenshot`/`both`, written to `--output` and returned as a
|
|
920
|
-
path, never inline). Pass `assert_contains="…"` to deterministically check the rendered
|
|
921
|
-
DOM contains a string — the robust "did the JS actually appear" check (beats eyeballing a
|
|
922
|
-
screenshot). If only **Firefox** is installed it degrades to screenshot-only (its
|
|
923
|
-
headless CLI can't dump the DOM); with no browser at all it reports "no headless browser
|
|
924
|
-
available," like the `git` rail.
|
|
911
|
+
`web_fetch` and `browser_capture` are temporarily unavailable while
|
|
912
|
+
[GHSA-mqjr-2vh8-6fvg](https://github.com/sirkitree/venice/security/advisories/GHSA-mqjr-2vh8-6fvg)
|
|
913
|
+
is contained. In v0.83.2, passing `--browser` exits with status 2 before loading the SDK,
|
|
914
|
+
credentials, or any network client. The direct implementation seams also return an error,
|
|
915
|
+
and the agent does not advertise either tool.
|
|
925
916
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
```
|
|
931
|
-
|
|
932
|
-
**URL safety.** The scheme must be `http`/`https` and the cloud-metadata endpoint
|
|
933
|
-
(`169.254.169.254`) is **always** blocked — these hard stops are not configurable. `file://`
|
|
934
|
-
and everything non-http is refused. On top of that, an operator **allow/deny** policy (CLI
|
|
935
|
-
flags add to a shared top-level `browser` section in [config](#config)) scopes which hosts
|
|
936
|
-
are reachable:
|
|
937
|
-
|
|
938
|
-
```sh
|
|
939
|
-
venice config set browser.deny '["*.internal", "10.*"]'
|
|
940
|
-
venice config set browser.allow '["localhost", "*.example.com"]'
|
|
941
|
-
```
|
|
942
|
-
|
|
943
|
-
- **Deny** globs match the URL host and the full URL, are always enforced, and win over
|
|
944
|
-
allow. A non-empty **allow** list restricts to matching hosts; empty = any host (still
|
|
945
|
-
subject to the hard stops + deny). `localhost` is reachable by default (the common case is
|
|
946
|
-
verifying a locally-served page).
|
|
947
|
-
- The headless browser runs untrusted page JS under an **allowlisted environment** (the
|
|
948
|
-
Venice API key and other ambient tokens are dropped) and a throwaway profile dir.
|
|
949
|
-
- DOM/text output and downloads are size-capped; tune with `defaults.browser.*`
|
|
950
|
-
(`wait_ms`, `timeout`, `max_bytes`).
|
|
951
|
-
- **Not exposed over `venice mcp-serve`** in this release (chat/code only), like
|
|
952
|
-
`project_search`/`reindex`.
|
|
917
|
+
The `--browser-allow`, `--browser-deny`, and `browser.*` config keys remain accepted only
|
|
918
|
+
to preserve existing configuration. They do not enable network access. Restoring this rail
|
|
919
|
+
requires an enforced egress boundary that covers redirects, DNS rebinding, browser
|
|
920
|
+
subresources, and page scripts—not another URL-only filter.
|
|
953
921
|
|
|
954
922
|
#### Web search (`--web-search`)
|
|
955
923
|
|
|
956
|
-
`--
|
|
957
|
-
other half of the loop — **discovery**. It adds one tool, `venice_web_search`, so the coding
|
|
924
|
+
`--web-search` adds one discovery tool, `venice_web_search`, so the coding
|
|
958
925
|
agent can look something up on the web when a fix needs documentation it doesn't have a link
|
|
959
926
|
for (an API's docs, a library's usage, an error message).
|
|
960
927
|
|
|
961
928
|
`venice_web_search(query)` makes **one** Venice web-search completion (server-side
|
|
962
929
|
`enable_web_search` + `enable_web_citations`, the same feature behind `venice chat
|
|
963
930
|
--web-search`) and returns a short **answer** plus the **cited URLs**. To then read a cited
|
|
964
|
-
page in full,
|
|
965
|
-
|
|
966
|
-
browser policy still governs what gets read.**
|
|
931
|
+
page in full, open it outside Venice: the direct `web_fetch` follow-up rail is temporarily
|
|
932
|
+
disabled as described above.
|
|
967
933
|
|
|
968
934
|
```sh
|
|
969
|
-
# discover
|
|
970
|
-
venice code --web-search --
|
|
935
|
+
# discover: search returns an answer and its cited URLs
|
|
936
|
+
venice code --web-search --auto \
|
|
971
937
|
"The stripe SDK call is failing with an idempotency error — look up the fix and apply it."
|
|
972
938
|
```
|
|
973
939
|
|
|
@@ -1020,7 +986,7 @@ venice memory tasks # the project checklist (--status filters)
|
|
|
1020
986
|
- **Locations:** project notes/tasks at `<root>/.venice/memory/` (git-ignored by default,
|
|
1021
987
|
like the semantic index); global notes at `~/.config/venice/memory/`
|
|
1022
988
|
(`$VENICE_MEMORY_DIR` overrides). All store files are `0600`.
|
|
1023
|
-
- **Hygiene (
|
|
989
|
+
- **Hygiene (AGENTS.md):** a note **name** is refused if it's secret-shaped
|
|
1024
990
|
(`credentials`, `id_rsa*`, `*.key`, `.env`, `*secrets*`, …), so the store can't be used
|
|
1025
991
|
to label or stash a credential.
|
|
1026
992
|
- **Not exposed over `venice mcp-serve`** (chat/code only), like the browser rails.
|
|
@@ -1425,7 +1391,7 @@ jq '.usage.billed_total' ~/.config/venice/sessions/<id>.json
|
|
|
1425
1391
|
| `run` | run a shell command (`/bin/sh -c`) at the **active** root | yes |
|
|
1426
1392
|
| `attach_root` | register another directory as a project root (for work spanning repos) and, by default, switch the active root into it so relative paths and `run`/`git` follow — writes outside the writable roots fail loudly | no |
|
|
1427
1393
|
| `venice_image` / `venice_image_edit` / `venice_sfx` / `venice_music` / `venice_tts` / `venice_upscale` / `venice_bg_remove` / `venice_video` | generate/edit images, audio & video into the project — **opt-in with `--assets`** | yes |
|
|
1428
|
-
| `web_fetch` / `browser_capture` |
|
|
1394
|
+
| `web_fetch` / `browser_capture` | temporarily unavailable for security; not advertised to the agent (see [Web & browser tools](#web--browser-tools---browser)) | no |
|
|
1429
1395
|
| `memory_write` / `memory_read` / `memory_search` / `memory_list` | durable notes the agent recalls across turns/sessions (two tiers: project + global) — **opt-in with `--memory`** (see [Memory & tasks](#memory--tasks---memory)) | no |
|
|
1430
1396
|
| `task_add` / `task_update` / `task_list` | a project-only checklist the agent tracks (`pending`/`in_progress`/`done`) — **opt-in with `--memory`** | no |
|
|
1431
1397
|
| `venice_scout` | delegate a read-only investigation to a disposable subagent with a fresh context; returns a structured report so exploration doesn't pollute the main context — **opt-in with `--scout`** (see [Scout subagent](#scout-subagent---scout)) | no |
|
|
@@ -1463,7 +1429,7 @@ it unrestricted (unchanged behavior).
|
|
|
1463
1429
|
| `--max-tool-calls N` | cap tool invocations before forcing a final answer (default 25) |
|
|
1464
1430
|
| `--exec-timeout SECS` | timeout for `run`/`git` (default 120) |
|
|
1465
1431
|
| `--shell-allow CMD` / `--shell-deny PATTERN` | scope the `run` tool with the shared allow/deny policy (repeatable; adds to config `shell.*`) |
|
|
1466
|
-
| `--browser` / `--browser-allow HOST` / `--browser-deny PATTERN` |
|
|
1432
|
+
| `--browser` / `--browser-allow HOST` / `--browser-deny PATTERN` | compatibility flags for the security-disabled browser rail; `--browser` exits 2 without network access (see [Web & browser tools](#web--browser-tools---browser)) |
|
|
1467
1433
|
| `--assets` | also expose the in-process asset-generation tools (image / image-edit / sfx / music / tts / upscale / bg-remove / video) so the agent can create images, audio & video in the project; paid — each confirms per call unless `--auto` |
|
|
1468
1434
|
| `--scout` | expose `venice_scout`: delegate a read-only investigation to a disposable subagent with a fresh context; keeps exploration out of the main context (see [Scout subagent](#scout-subagent---scout)) |
|
|
1469
1435
|
| `--spawn` | expose `venice_spawn`: delegate a bounded **write/paid** task to a disposable **worker** subagent with a fresh context and a role-scoped subset of your tools; edit churn stays quarantined and it returns a structured report to merge (see [Worker subagent](#worker-subagent---spawn)) |
|
|
@@ -1471,7 +1437,7 @@ it unrestricted (unchanged behavior).
|
|
|
1471
1437
|
| `--subagent-max-tokens N` | per-subagent cap on the cumulative prompt+completion **tokens** a `venice_scout` **or** `venice_spawn` subagent spends across its turns (default **off**; `<= 0` disables); once crossed the subagent is asked to wrap up and its report carries the token count. A cumulative-usage ceiling, **not** a context-window size limit, and distinct from `--max-tokens` (per-turn output); config `defaults.code.subagent_max_tokens` |
|
|
1472
1438
|
| `--planner` | planner harness: implies `--scout --spawn --memory`, mandates the decompose → dispatch → track → **merge** protocol, and adds `venice_merge` — a consolidated rollup of every dispatch (see [Planner harness](#planner-harness---planner)) |
|
|
1473
1439
|
| `--parallel` | dispatch **independent** `venice_scout`/`venice_spawn` subagents **concurrently** (bounded pool) instead of one at a time, so a planner's independent units overlap in wall-clock; opt-in, serial otherwise; config `defaults.code.parallel` (see [Parallel dispatch](#parallel-dispatch---parallel)) |
|
|
1474
|
-
| `--web-search` / `--web-search-model MODEL` | expose `venice_web_search` so the agent can **discover** documentation on the web (answer + cited URLs
|
|
1440
|
+
| `--web-search` / `--web-search-model MODEL` | expose `venice_web_search` so the agent can **discover** documentation on the web (answer + cited URLs; see [Web search](#web-search---web-search)) |
|
|
1475
1441
|
| `--review` | expose `venice_review`: hand the current diff to a **cold-context reviewer** (fresh context, read-only tools, a different model where one exists) and fix what it reports before handing work back. Capped at **3 reviews per session**. Findings only — a review is not a merge gate (see [Reviewer rail](#reviewer-rail---review)) |
|
|
1476
1442
|
| `--review-model MODEL` | model for `--review` (default: a function-calling model from a **different family** than the coding model; falls back to the coding model with a warning); config `defaults.code.review_model` |
|
|
1477
1443
|
| `--review-rounds N` | passes `venice_review` makes over the same diff (default **1**, max 3); config `defaults.code.review_rounds` |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.83.2"
|
|
@@ -70,7 +70,6 @@ class VeniceClient:
|
|
|
70
70
|
url += "?" + urllib.parse.urlencode(params, doseq=True)
|
|
71
71
|
|
|
72
72
|
headers = {
|
|
73
|
-
"Authorization": f"Bearer {self.api_key}",
|
|
74
73
|
"Accept": "application/json, audio/*, image/*, video/*",
|
|
75
74
|
"User-Agent": self.user_agent,
|
|
76
75
|
}
|
|
@@ -80,6 +79,12 @@ class VeniceClient:
|
|
|
80
79
|
headers["Content-Type"] = "application/json"
|
|
81
80
|
|
|
82
81
|
req = urllib.request.Request(url, data=data, headers=headers, method=method)
|
|
82
|
+
# Bind the credential to this request. urllib copies regular headers
|
|
83
|
+
# when it constructs a redirected request, but deliberately leaves
|
|
84
|
+
# unredirected headers behind.
|
|
85
|
+
req.add_unredirected_header(
|
|
86
|
+
"Authorization", f"Bearer {self.api_key}"
|
|
87
|
+
)
|
|
83
88
|
try:
|
|
84
89
|
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
|
|
85
90
|
body = resp.read()
|
|
@@ -1695,8 +1695,8 @@ def dispatch_map(tools: List[Tool]) -> Dict[str, Tool]:
|
|
|
1695
1695
|
|
|
1696
1696
|
# --------------------------------------------------------------------------- #
|
|
1697
1697
|
# Web search (#77): one server-side Venice completion with `enable_web_search`, so
|
|
1698
|
-
# the coding agent / scout can DISCOVER documentation
|
|
1699
|
-
#
|
|
1698
|
+
# the coding agent / scout can DISCOVER documentation and return citations. Rides the
|
|
1699
|
+
# normal completion path (same
|
|
1700
1700
|
# key, same billing), so the per-agent tool-call budget bounds it. The `venice_web_search`
|
|
1701
1701
|
# rail Tool wrapper + `supportsWebSearch` model resolution live in `_code`; this module
|
|
1702
1702
|
# owns only the profile-agnostic completion helper.
|
|
@@ -2435,67 +2435,13 @@ def _tool_section(name: str) -> str:
|
|
|
2435
2435
|
return name[len("venice_"):] if name.startswith("venice_") else name
|
|
2436
2436
|
|
|
2437
2437
|
|
|
2438
|
-
def _browser_args(arguments) -> dict:
|
|
2439
|
-
"""Model-supplied browser-tool args with policy/loop-controlled keys stripped: the
|
|
2440
|
-
model must not set `allow`/`deny` (widen its URL policy) or the loop-controlled keys."""
|
|
2441
|
-
return {k: v for k, v in _clean(arguments).items() if k not in ("allow", "deny")}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
2438
|
def browser_tools(*, allow=(), deny=(), output_dir=None, config=None) -> List[Tool]:
|
|
2445
|
-
"""
|
|
2439
|
+
"""Return no browser tools while the browser rail is security-disabled.
|
|
2446
2440
|
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
knobs still honor `defaults.browser.*` (#58), layered under the model's arguments.
|
|
2450
|
-
Both tools are free (no spend gate) and never require confirmation; the URL policy is
|
|
2451
|
-
the guard.
|
|
2441
|
+
Keep this compatibility seam so callers cannot accidentally re-expose the direct
|
|
2442
|
+
tool implementations while GHSA-mqjr-2vh8-6fvg is contained.
|
|
2452
2443
|
"""
|
|
2453
|
-
|
|
2454
|
-
cap_defaults = userconfig.config_defaults_for("browser", _mcp.browser_capture_tool, config)
|
|
2455
|
-
|
|
2456
|
-
def _web_fetch_invoke(arguments, *, confirm: bool = False):
|
|
2457
|
-
return _mcp.web_fetch_tool(
|
|
2458
|
-
allow=allow, deny=deny, **{**fetch_defaults, **_browser_args(arguments)})
|
|
2459
|
-
|
|
2460
|
-
def _browser_capture_invoke(arguments, *, confirm: bool = False):
|
|
2461
|
-
return _mcp.browser_capture_tool(
|
|
2462
|
-
allow=allow, deny=deny, output_dir=output_dir,
|
|
2463
|
-
**{**cap_defaults, **_browser_args(arguments)})
|
|
2464
|
-
|
|
2465
|
-
return [
|
|
2466
|
-
Tool(
|
|
2467
|
-
name="web_fetch",
|
|
2468
|
-
description=(
|
|
2469
|
-
"Fetch an http(s) URL with stdlib urllib and return its text (mode=text, "
|
|
2470
|
-
"default) or raw HTML (mode=html). Zero-dep; good for non-SPA pages. For "
|
|
2471
|
-
"JS-rendered pages use browser_capture. Read-only; not spend-gated. "
|
|
2472
|
-
"file://, the cloud metadata endpoint, and any host the operator denies "
|
|
2473
|
-
"are refused."
|
|
2474
|
-
),
|
|
2475
|
-
parameters=_WEB_FETCH_SCHEMA,
|
|
2476
|
-
invoke=_web_fetch_invoke,
|
|
2477
|
-
paid=False,
|
|
2478
|
-
category="web",
|
|
2479
|
-
tags=("read", "network"),
|
|
2480
|
-
),
|
|
2481
|
-
Tool(
|
|
2482
|
-
name="browser_capture",
|
|
2483
|
-
description=(
|
|
2484
|
-
"Headless-render an http(s) URL and return the post-JS DOM (mode=dom/text) "
|
|
2485
|
-
"and/or a screenshot PNG path (mode=screenshot/both) -- use it to verify a "
|
|
2486
|
-
"page's JS-injected content actually appeared. Pass assert_contains to "
|
|
2487
|
-
"check the DOM contains a substring (deterministic). DOM modes need a "
|
|
2488
|
-
"Chromium-family browser (Firefox is screenshot-only); reports 'no "
|
|
2489
|
-
"headless browser available' when none is installed. Read-only; not "
|
|
2490
|
-
"spend-gated."
|
|
2491
|
-
),
|
|
2492
|
-
parameters=_BROWSER_CAPTURE_SCHEMA,
|
|
2493
|
-
invoke=_browser_capture_invoke,
|
|
2494
|
-
paid=False,
|
|
2495
|
-
category="web",
|
|
2496
|
-
tags=("read", "network"),
|
|
2497
|
-
),
|
|
2498
|
-
]
|
|
2444
|
+
return []
|
|
2499
2445
|
|
|
2500
2446
|
|
|
2501
2447
|
def memory_tools() -> List[Tool]:
|
|
@@ -2646,8 +2592,8 @@ def builtin_tools(
|
|
|
2646
2592
|
rail, not a venice API tool, so it isn't part of the selectable `_BUILTINS`
|
|
2647
2593
|
set) and is never exposed via `mcp-serve`, which builds its own wrappers.
|
|
2648
2594
|
|
|
2649
|
-
`browser` (issue #71)
|
|
2650
|
-
|
|
2595
|
+
`browser` (issue #71) is retained as a compatibility argument but appends no tools
|
|
2596
|
+
while GHSA-mqjr-2vh8-6fvg is contained (see `browser_tools`).
|
|
2651
2597
|
|
|
2652
2598
|
`memory` (issue #49) appends the persistent memory + task rails (`memory_tools`):
|
|
2653
2599
|
free, local notes (two tiers) + a project task list. Also a rail (added after the
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Fail-closed browser rail containment.
|
|
2
|
+
|
|
3
|
+
The former implementation launched a headless browser after checking only the
|
|
4
|
+
initial URL. Redirects, DNS resolution, subresources, and page-script requests
|
|
5
|
+
then escaped that policy boundary. Until the rail has an enforced egress
|
|
6
|
+
boundary, keep every entry point unavailable and dependency-free.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
UNAVAILABLE_MESSAGE = (
|
|
12
|
+
"web and browser tools are temporarily disabled for security; "
|
|
13
|
+
"see GHSA-mqjr-2vh8-6fvg"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def web_fetch(
|
|
18
|
+
url, *, mode="text", max_bytes=None, timeout=None, allow=(), deny=()
|
|
19
|
+
) -> dict:
|
|
20
|
+
"""Fail closed without parsing, resolving, or opening ``url``."""
|
|
21
|
+
return {"ok": False, "error": UNAVAILABLE_MESSAGE}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def capture(
|
|
25
|
+
url, *, out_path=None, mode="dom", wait_ms=None, window=None,
|
|
26
|
+
timeout=None, assert_contains=None, allow=(), deny=(),
|
|
27
|
+
) -> dict:
|
|
28
|
+
"""Fail closed without probing or launching a browser."""
|
|
29
|
+
return {"ok": False, "error": UNAVAILABLE_MESSAGE}
|
|
@@ -812,8 +812,8 @@ def code_tools(
|
|
|
812
812
|
Empty lists leave `run` unrestricted (only the confirm gate), preserving the prior
|
|
813
813
|
behavior of autonomous `venice code` runs.
|
|
814
814
|
|
|
815
|
-
`browser` (#71)
|
|
816
|
-
|
|
815
|
+
`browser` (#71) is retained for call compatibility but appends no tools while
|
|
816
|
+
GHSA-mqjr-2vh8-6fvg is contained (see `_agent.browser_tools`).
|
|
817
817
|
|
|
818
818
|
`memory` (#49) appends the persistent memory + task rails (`_agent.memory_tools`):
|
|
819
819
|
free, local notes (two tiers) + a project task list the agent maintains across
|
|
@@ -956,8 +956,8 @@ def code_tools(
|
|
|
956
956
|
))
|
|
957
957
|
|
|
958
958
|
if browser:
|
|
959
|
-
#
|
|
960
|
-
#
|
|
959
|
+
# Compatibility seam only: browser_tools returns [] while the rail is disabled
|
|
960
|
+
# for GHSA-mqjr-2vh8-6fvg.
|
|
961
961
|
tools.extend(_agent.browser_tools(
|
|
962
962
|
allow=browser_allow, deny=browser_deny,
|
|
963
963
|
output_dir=os.environ.get("VENICE_MCP_OUTPUT_DIR") or root,
|
|
@@ -1135,9 +1135,8 @@ def web_search_tool(oai, model: str, *, models=None, search_model=None,
|
|
|
1135
1135
|
|
|
1136
1136
|
Makes one Venice web-search completion (via `_agent.run_web_search`) against a
|
|
1137
1137
|
`supportsWebSearch` model and returns the answer plus the cited URLs. The agent
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
policy governs what gets read.
|
|
1138
|
+
returns citations for the operator to inspect. The former direct `web_fetch` follow-up
|
|
1139
|
+
rail is disabled while GHSA-mqjr-2vh8-6fvg is contained.
|
|
1141
1140
|
|
|
1142
1141
|
`paid=False` mirrors `venice_chat` (a bounded, billed sub-completion, not a media
|
|
1143
1142
|
purchase): it MUST be free so a read-only SCOUT can carry it (`_agent.run_scout`
|
|
@@ -1181,9 +1180,8 @@ def web_search_tool(oai, model: str, *, models=None, search_model=None,
|
|
|
1181
1180
|
_agent.WEB_SEARCH_TOOL_NAME,
|
|
1182
1181
|
"Search the web for documentation or answers and get back a short summary plus "
|
|
1183
1182
|
"the source URLs it cited. Use it to DISCOVER pages you do not already have a URL "
|
|
1184
|
-
"for (API docs, library usage, an error message).
|
|
1185
|
-
"
|
|
1186
|
-
"commands.",
|
|
1183
|
+
"for (API docs, library usage, an error message). Read-only; cannot edit files "
|
|
1184
|
+
"or run commands.",
|
|
1187
1185
|
_agent._WEB_SEARCH_SCHEMA, invoke, paid=False,
|
|
1188
1186
|
category="web", tags=("read", "network"),
|
|
1189
1187
|
)
|
|
@@ -37,7 +37,7 @@ from typing import Optional
|
|
|
37
37
|
MAX_OUTPUT_CHARS = 20_000 # cap per stdout/stderr stream
|
|
38
38
|
DEFAULT_EXEC_TIMEOUT = 120 # seconds
|
|
39
39
|
|
|
40
|
-
# Secrets never inherited into an exec'd child (
|
|
40
|
+
# Secrets never inherited into an exec'd child (AGENTS.md credential hygiene).
|
|
41
41
|
_SECRET_ENV = ("VENICE_API_KEY", "VENICE_EMBED_API_KEY")
|
|
42
42
|
|
|
43
43
|
# Substrings that turn `/bin/sh -c` into more than a single simple command. When an
|
|
@@ -61,7 +61,7 @@ _DIR_DENYLIST = frozenset({
|
|
|
61
61
|
"env", ".idea", ".vscode", "dist", "build", ".egg-info",
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
# Exact filenames never indexed (credential/secret-shaped --
|
|
64
|
+
# Exact filenames never indexed (credential/secret-shaped -- AGENTS.md invariant).
|
|
65
65
|
_SECRET_NAMES = frozenset({"credentials", ".env", ".netrc", ".pgpass"})
|
|
66
66
|
# Glob patterns (matched on basename) never indexed.
|
|
67
67
|
_SECRET_GLOBS = (
|
|
@@ -18,7 +18,7 @@ channel):
|
|
|
18
18
|
* Consumed in ``(mtime, name)`` order and deleted on read; a queued message
|
|
19
19
|
survives an agent restart -- ``--resume`` drains it on the loop's first turn.
|
|
20
20
|
|
|
21
|
-
Trust model (
|
|
21
|
+
Trust model (AGENTS.md): a steer is *additive user input* at the same trust level
|
|
22
22
|
as the original task author. The mailbox is a local, owner-only directory, NOT a
|
|
23
23
|
remote-control channel; nothing here reads or writes the API key.
|
|
24
24
|
"""
|
|
@@ -1205,32 +1205,8 @@ def web_fetch_tool(
|
|
|
1205
1205
|
url, *, mode: str = "text", max_bytes: Optional[int] = None,
|
|
1206
1206
|
timeout: Optional[int] = None, allow=(), deny=(),
|
|
1207
1207
|
) -> dict:
|
|
1208
|
-
"""
|
|
1209
|
-
|
|
1210
|
-
Read-only, no browser, zero extra deps -- good for non-SPA "read this page". For
|
|
1211
|
-
JS-rendered pages use `browser_capture`. Not spend-gated. URL safety: only http/https,
|
|
1212
|
-
the cloud metadata endpoint is always blocked, redirects are re-checked against the
|
|
1213
|
-
policy, and the operator's browser allow/deny globs apply. `allow`/`deny` are supplied
|
|
1214
|
-
by the tool wiring (bound from config), never by the model.
|
|
1215
|
-
"""
|
|
1216
|
-
if not url or not str(url).strip():
|
|
1217
|
-
return _err("web_fetch: url is required")
|
|
1218
|
-
res = _browser.web_fetch(str(url), mode=(mode or "text"), max_bytes=max_bytes,
|
|
1219
|
-
timeout=timeout, allow=allow, deny=deny)
|
|
1220
|
-
if not res.get("ok"):
|
|
1221
|
-
return _err(f"web_fetch: {res.get('error', 'failed')}")
|
|
1222
|
-
out = {
|
|
1223
|
-
"status": "ok",
|
|
1224
|
-
"url": str(url),
|
|
1225
|
-
"final_url": res.get("final_url"),
|
|
1226
|
-
"content_type": res.get("content_type"),
|
|
1227
|
-
"truncated": res.get("truncated", False),
|
|
1228
|
-
}
|
|
1229
|
-
if "text" in res:
|
|
1230
|
-
out["text"] = res["text"]
|
|
1231
|
-
if "html" in res:
|
|
1232
|
-
out["html"] = res["html"]
|
|
1233
|
-
return out
|
|
1208
|
+
"""Fail closed while the browser rail has no enforced egress boundary."""
|
|
1209
|
+
return _err(f"web_fetch: {_browser.UNAVAILABLE_MESSAGE}")
|
|
1234
1210
|
|
|
1235
1211
|
|
|
1236
1212
|
def browser_capture_tool(
|
|
@@ -1238,48 +1214,8 @@ def browser_capture_tool(
|
|
|
1238
1214
|
assert_contains: Optional[str] = None, output_dir: Optional[str] = None,
|
|
1239
1215
|
allow=(), deny=(),
|
|
1240
1216
|
) -> dict:
|
|
1241
|
-
"""
|
|
1242
|
-
|
|
1243
|
-
Chromium-family browsers (chromium/chrome/brave) give a post-JS DOM (mode `dom`/`text`)
|
|
1244
|
-
and/or a screenshot; Firefox is a screenshot-only fallback. Writes any screenshot to the
|
|
1245
|
-
output dir and returns its PATH (never an inline blob, like `venice_image`); returns the
|
|
1246
|
-
DOM inline (capped). Pass `assert_contains` to deterministically check the rendered DOM
|
|
1247
|
-
contains a substring -- the robust "did the JS land" check (beats eyeballing a shot).
|
|
1248
|
-
Degrades gracefully ("no headless browser available") when no browser is installed. Not
|
|
1249
|
-
spend-gated. URL safety mirrors `web_fetch`; `allow`/`deny` come from the wiring, not the
|
|
1250
|
-
model.
|
|
1251
|
-
"""
|
|
1252
|
-
if not url or not str(url).strip():
|
|
1253
|
-
return _err("browser_capture: url is required")
|
|
1254
|
-
m = mode or "dom"
|
|
1255
|
-
out_path = None
|
|
1256
|
-
if m in ("screenshot", "both"):
|
|
1257
|
-
out_dir = resolve_output_dir(output_dir)
|
|
1258
|
-
try:
|
|
1259
|
-
out_dir.mkdir(parents=True, exist_ok=True)
|
|
1260
|
-
except OSError as e:
|
|
1261
|
-
return _err(f"browser_capture: cannot create output dir {out_dir}: {e}")
|
|
1262
|
-
out_path = str(out_dir / _browser.capture_filename(url))
|
|
1263
|
-
res = _browser.capture(str(url), out_path=out_path, mode=m, wait_ms=wait_ms,
|
|
1264
|
-
timeout=timeout, assert_contains=assert_contains,
|
|
1265
|
-
allow=allow, deny=deny)
|
|
1266
|
-
if not res.get("ok"):
|
|
1267
|
-
return _err(f"browser_capture: {res.get('error', 'failed')}")
|
|
1268
|
-
out = {"status": "ok", "url": str(url), "mode": m,
|
|
1269
|
-
"browser": res.get("browser"), "family": res.get("family")}
|
|
1270
|
-
if res.get("screenshot_path"):
|
|
1271
|
-
out["screenshot_path"] = res["screenshot_path"]
|
|
1272
|
-
if "dom" in res:
|
|
1273
|
-
out["dom"] = res["dom"]
|
|
1274
|
-
out["truncated"] = res.get("truncated", False)
|
|
1275
|
-
if "contains" in res:
|
|
1276
|
-
out["assert_contains"] = res.get("assert_contains")
|
|
1277
|
-
out["contains"] = res["contains"]
|
|
1278
|
-
elif assert_contains is not None:
|
|
1279
|
-
out["assert_contains"] = str(assert_contains)
|
|
1280
|
-
out["contains"] = None
|
|
1281
|
-
out["note"] = "assert_contains needs a DOM (mode dom/text/both on a Chromium browser)"
|
|
1282
|
-
return out
|
|
1217
|
+
"""Fail closed while the browser rail has no enforced egress boundary."""
|
|
1218
|
+
return _err(f"browser_capture: {_browser.UNAVAILABLE_MESSAGE}")
|
|
1283
1219
|
|
|
1284
1220
|
|
|
1285
1221
|
def models_tool(client, *, type: str) -> dict:
|
|
@@ -28,7 +28,7 @@ file. The lock is **in-process only**: two separate ``venice`` processes writing
|
|
|
28
28
|
store remain last-writer-wins (like ``secrets.json`` / ``sessions`` / the index) -- guard
|
|
29
29
|
that with per-entry files or an OS lock if it ever becomes real; callers need not change.
|
|
30
30
|
|
|
31
|
-
Hygiene (
|
|
31
|
+
Hygiene (AGENTS.md): an entry NAME is validated like a persona/secret name (no
|
|
32
32
|
traversal) and refused if secret-shaped (``is_secret_path``) so the store can't be
|
|
33
33
|
used to label/stash credentials; the name is only ever a dict key, so there is no
|
|
34
34
|
filesystem-path surface. The store lives under ``.venice/`` -- already pruned by
|
|
@@ -17,7 +17,7 @@ Slash-commands (minimal set): ``/system`` ``/model`` ``/reset`` ``/save``
|
|
|
17
17
|
``/exit`` (plus ``/help`` and the ``/quit`` alias). Transcripts round-trip as a
|
|
18
18
|
JSON list of messages via ``--resume FILE`` and ``/save``.
|
|
19
19
|
|
|
20
|
-
Secret hygiene (
|
|
20
|
+
Secret hygiene (AGENTS.md): the REPL prints only model output and message
|
|
21
21
|
content; it never echoes the API key. A saved transcript holds only the
|
|
22
22
|
``messages`` array (roles + content), never auth material.
|
|
23
23
|
"""
|