javis 0.2.0__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.
- javis/__init__.py +7 -0
- javis/_banner.py +69 -0
- javis/budget.py +17 -0
- javis/builtin_marketplace/code-review/agents/reviewer.md +9 -0
- javis/builtin_marketplace/code-review/commands/review.md +16 -0
- javis/builtin_marketplace/code-review/plugin.json +4 -0
- javis/builtin_marketplace/commit/commands/commit.md +13 -0
- javis/builtin_marketplace/commit/plugin.json +4 -0
- javis/builtin_marketplace/explain/agents/explainer.md +7 -0
- javis/builtin_marketplace/explain/commands/explain.md +15 -0
- javis/builtin_marketplace/explain/plugin.json +4 -0
- javis/builtin_marketplace/test-author/agents/test-author.md +8 -0
- javis/builtin_marketplace/test-author/commands/test.md +12 -0
- javis/builtin_marketplace/test-author/plugin.json +4 -0
- javis/caching.py +39 -0
- javis/catalog.py +68 -0
- javis/cli.py +644 -0
- javis/commands.py +77 -0
- javis/compress.py +33 -0
- javis/config.py +60 -0
- javis/context.py +111 -0
- javis/core.py +56 -0
- javis/distill.py +74 -0
- javis/errors.py +120 -0
- javis/eval.py +281 -0
- javis/eval_ab.py +133 -0
- javis/events.py +131 -0
- javis/experiment.py +214 -0
- javis/failure_memory.py +97 -0
- javis/gates/__init__.py +0 -0
- javis/gates/base.py +16 -0
- javis/gates/lint.py +36 -0
- javis/gates/oracle.py +78 -0
- javis/gates/parse.py +31 -0
- javis/gates/policy.py +108 -0
- javis/gates/readwrite.py +28 -0
- javis/gates/resolve.py +213 -0
- javis/gates/verify.py +13 -0
- javis/guardrails.py +107 -0
- javis/hooks.py +127 -0
- javis/ladders.py +75 -0
- javis/languages.py +145 -0
- javis/localproto.py +126 -0
- javis/loop.py +623 -0
- javis/lsp.py +350 -0
- javis/marketplace.py +212 -0
- javis/mcp.py +459 -0
- javis/mcp_install.py +184 -0
- javis/model.py +96 -0
- javis/narrator.py +85 -0
- javis/orchestrate.py +341 -0
- javis/permissions.py +108 -0
- javis/plan.py +112 -0
- javis/planmode.py +28 -0
- javis/plugins.py +324 -0
- javis/polyglot.py +309 -0
- javis/preflight.py +180 -0
- javis/ratelimit.py +89 -0
- javis/redact.py +36 -0
- javis/repomap.py +83 -0
- javis/router.py +125 -0
- javis/sanitize.py +44 -0
- javis/semsearch.py +171 -0
- javis/setup.py +84 -0
- javis/slash.py +101 -0
- javis/subagents.py +155 -0
- javis/swebench.py +385 -0
- javis/swebench_docker.py +136 -0
- javis/theme.py +99 -0
- javis/tools/__init__.py +0 -0
- javis/tools/code.py +101 -0
- javis/tools/fs.py +139 -0
- javis/tools/git.py +32 -0
- javis/tools/shell.py +23 -0
- javis/tools/tests.py +158 -0
- javis/trajectory.py +59 -0
- javis/treesitter.py +266 -0
- javis/tui.py +910 -0
- javis/tui_app.py +284 -0
- javis-0.2.0.dist-info/METADATA +200 -0
- javis-0.2.0.dist-info/RECORD +86 -0
- javis-0.2.0.dist-info/WHEEL +5 -0
- javis-0.2.0.dist-info/entry_points.txt +10 -0
- javis-0.2.0.dist-info/licenses/LICENSE +202 -0
- javis-0.2.0.dist-info/licenses/NOTICE +4 -0
- javis-0.2.0.dist-info/top_level.txt +1 -0
javis/__init__.py
ADDED
javis/_banner.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Generated by scripts/gen_banner.py from the JAVIS logo. Do not edit by hand.
|
|
2
|
+
HERO/LOGO are rich markup (crimson scorpion / white shield); *_PLAIN strip the tags."""
|
|
3
|
+
|
|
4
|
+
HERO = r'''
|
|
5
|
+
[#f5f5f5]▒▓▓▒▒[/] [#e10600]▓█████▓[/] [#e10600]▓█████▒[/] [#f5f5f5]▒▓▓▓▒[/]
|
|
6
|
+
[#f5f5f5]▓██▓[/] [#e10600]▒██████▓[/] [#e10600]▒▓[/] [#e10600]▓▒[/] [#e10600]▓██████▓[/] [#f5f5f5]▓██▓[/]
|
|
7
|
+
[#f5f5f5]█▓[/] [#e10600]▒▓███████▓███▒[/] [#e10600]██[/] [#e10600]▓█[/] [#e10600]▒███▓████████[/] [#f5f5f5]▓█▒[/]
|
|
8
|
+
[#f5f5f5]▓█[/] [#e10600]▓▓▓████▓██▓[/] [#e10600]█████[/] [#e10600]▒██▓█████▓█▓[/] [#f5f5f5]█▓[/]
|
|
9
|
+
[#f5f5f5]▓█[/] [#e10600]████▓[/] [#e10600]▒██▒███████▒██▒[/] [#e10600]▓████[/] [#f5f5f5]▓▓[/]
|
|
10
|
+
[#f5f5f5]▓▓[/] [#e10600]█████[/] [#e10600]▒████▓████████▓███▓[/] [#e10600]█████[/] [#f5f5f5]▓▓[/]
|
|
11
|
+
[#f5f5f5]▒▒[/] [#e10600]████▓████▓█████████▓████▓▓███[/] [#f5f5f5]▒[/]
|
|
12
|
+
[#e10600]██▒████▒[/] [#e10600]▓████████[/] [#e10600]▒▓███▒██[/]
|
|
13
|
+
[#e10600]▒[/] [#e10600]▒[/] [#e10600]▓█████▓[/] [#e10600]▒[/]
|
|
14
|
+
[#e10600]▒██▓[/] [#e10600]█▓▓▓▒██[/]
|
|
15
|
+
[#e10600]▓███▓[/] [#e10600]█████▓[/]
|
|
16
|
+
[#e10600]▓██▓[/] [#e10600]▓██▓███[/]
|
|
17
|
+
[#f5f5f5]▒[/][#e10600]▒████[/] [#e10600]▓████▒[/] [#f5f5f5]▒[/]
|
|
18
|
+
[#f5f5f5]▒▓[/] [#e10600]▓█▓█▓[/] [#e10600]▓███▓[/] [#f5f5f5]▓▒[/]
|
|
19
|
+
[#f5f5f5]▓▓[/] [#e10600]▓███▒███▓[/] [#f5f5f5]▓▓[/]
|
|
20
|
+
[#f5f5f5]▒█▓[/] [#e10600]▓█▓█▓[/] [#f5f5f5]▒█▓[/]
|
|
21
|
+
[#f5f5f5]▓█▓[/] [#f5f5f5]▒█▓[/]
|
|
22
|
+
[#f5f5f5]▒██▓██▒[/]
|
|
23
|
+
[#f5f5f5]▒█▒[/]
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
HERO_PLAIN = r'''
|
|
27
|
+
▒▓▓▒▒ ▓█████▓ ▓█████▒ ▒▓▓▓▒
|
|
28
|
+
▓██▓ ▒██████▓ ▒▓ ▓▒ ▓██████▓ ▓██▓
|
|
29
|
+
█▓ ▒▓███████▓███▒ ██ ▓█ ▒███▓████████ ▓█▒
|
|
30
|
+
▓█ ▓▓▓████▓██▓ █████ ▒██▓█████▓█▓ █▓
|
|
31
|
+
▓█ ████▓ ▒██▒███████▒██▒ ▓████ ▓▓
|
|
32
|
+
▓▓ █████ ▒████▓████████▓███▓ █████ ▓▓
|
|
33
|
+
▒▒ ████▓████▓█████████▓████▓▓███ ▒
|
|
34
|
+
██▒████▒ ▓████████ ▒▓███▒██
|
|
35
|
+
▒ ▒ ▓█████▓ ▒
|
|
36
|
+
▒██▓ █▓▓▓▒██
|
|
37
|
+
▓███▓ █████▓
|
|
38
|
+
▓██▓ ▓██▓███
|
|
39
|
+
▒▒████ ▓████▒ ▒
|
|
40
|
+
▒▓ ▓█▓█▓ ▓███▓ ▓▒
|
|
41
|
+
▓▓ ▓███▒███▓ ▓▓
|
|
42
|
+
▒█▓ ▓█▓█▓ ▒█▓
|
|
43
|
+
▓█▓ ▒█▓
|
|
44
|
+
▒██▓██▒
|
|
45
|
+
▒█▒
|
|
46
|
+
'''
|
|
47
|
+
|
|
48
|
+
LOGO = r'''
|
|
49
|
+
[#e10600]▓▒[/] [#e10600]▓[/]
|
|
50
|
+
[#f5f5f5]▒▓[/][#e10600]▓███▓▒▓▒████[/][#f5f5f5]▒▓[/]
|
|
51
|
+
[#f5f5f5]▓[/][#e10600]██▓██████▓██▒[/][#f5f5f5]▒[/]
|
|
52
|
+
[#e10600]▓▓█▓███▓█▓▒[/]
|
|
53
|
+
[#e10600]█▓██▓[/]
|
|
54
|
+
[#e10600]▓█▓▓█▒[/]
|
|
55
|
+
[#f5f5f5]▓[/][#e10600]▓▓[/][#f5f5f5]▓▒[/]
|
|
56
|
+
[#f5f5f5]▒▓[/]
|
|
57
|
+
'''
|
|
58
|
+
|
|
59
|
+
LOGO_PLAIN = r'''
|
|
60
|
+
▓▒ ▓
|
|
61
|
+
▒▓▓███▓▒▓▒████▒▓
|
|
62
|
+
▓██▓██████▓██▒▒
|
|
63
|
+
▓▓█▓███▓█▓▒
|
|
64
|
+
█▓██▓
|
|
65
|
+
▓█▓▓█▒
|
|
66
|
+
▓▓▓▓▒
|
|
67
|
+
▒▓
|
|
68
|
+
'''
|
|
69
|
+
|
javis/budget.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Run budget — so a thrashing weak model can't burn unbounded tokens (non-negotiable #7)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Budget:
|
|
10
|
+
max_steps: int = 40
|
|
11
|
+
used: int = 0
|
|
12
|
+
|
|
13
|
+
def tick(self) -> None:
|
|
14
|
+
self.used += 1
|
|
15
|
+
|
|
16
|
+
def exhausted(self) -> bool:
|
|
17
|
+
return self.used >= self.max_steps
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Focused code reviewer — finds defensible defects in a diff or file and grades severity.
|
|
3
|
+
model: opus
|
|
4
|
+
---
|
|
5
|
+
You are a precise code reviewer. Given a diff or a file, surface only defects you can defend from the
|
|
6
|
+
code itself: logic errors, unhandled edge cases, security issues, and broken invariants. For each one
|
|
7
|
+
give `file:line`, the reason it is wrong, and the smallest fix. Rank findings by severity and finish
|
|
8
|
+
with a verdict — APPROVE, APPROVE-WITH-NITS, or REQUEST-CHANGES. Never pad the list to seem thorough;
|
|
9
|
+
a short, correct review beats a long, speculative one.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Review the staged diff (or a given path) for correctness, security, and regressions.
|
|
3
|
+
---
|
|
4
|
+
Review the code changes for **correctness, security, and regressions** — be specific and cite `file:line`.
|
|
5
|
+
|
|
6
|
+
Target: $ARGUMENTS
|
|
7
|
+
(If that is empty, review the staged diff: `git diff --cached`.)
|
|
8
|
+
|
|
9
|
+
Do this:
|
|
10
|
+
1. If a path was given, read it; otherwise inspect the staged diff.
|
|
11
|
+
2. Find concrete defects, ordered by severity — logic errors, unhandled edge cases, security issues
|
|
12
|
+
(injection, path traversal, leaked secrets), and broken invariants or missing tests.
|
|
13
|
+
3. For each finding give: the location, why it is wrong, and the smallest fix.
|
|
14
|
+
4. End with a one-line verdict: APPROVE, APPROVE-WITH-NITS, or REQUEST-CHANGES.
|
|
15
|
+
|
|
16
|
+
Report only what you can defend from the code. Do not invent issues to look thorough.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Draft a Conventional-Commits message from the staged diff.
|
|
3
|
+
---
|
|
4
|
+
Write a commit message for the currently staged changes.
|
|
5
|
+
|
|
6
|
+
1. Read the staged diff: `git diff --cached`. If nothing is staged, say so and stop.
|
|
7
|
+
2. Summarise the *intent* of the change, not a file-by-file list.
|
|
8
|
+
3. Format as Conventional Commits: `type(scope): subject` (subject ≤72 chars), a blank line, then
|
|
9
|
+
1–3 short body bullets if the change warrants explanation. Types: feat, fix, refactor, docs, test,
|
|
10
|
+
chore, perf.
|
|
11
|
+
4. Output only the commit message, ready to paste — no preamble, no fences.
|
|
12
|
+
|
|
13
|
+
Extra context from the user (optional): $ARGUMENTS
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Explains code clearly and accurately, grounded in the actual source.
|
|
3
|
+
tier: cheap
|
|
4
|
+
---
|
|
5
|
+
You explain code for someone who is about to modify it. Read the target first, then cover its purpose,
|
|
6
|
+
the main control flow, edge cases, and risks — each grounded in a `file:line` you actually read. Be
|
|
7
|
+
concise and concrete. If something cannot be determined from the code, say so rather than guessing.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Explain a file or symbol — intent, control flow, edge cases, and risks.
|
|
3
|
+
---
|
|
4
|
+
Explain the target so a new contributor could safely change it.
|
|
5
|
+
|
|
6
|
+
Target: $ARGUMENTS
|
|
7
|
+
(A path, or a symbol name to locate first.)
|
|
8
|
+
|
|
9
|
+
Cover, briefly:
|
|
10
|
+
1. **Purpose** — what it is for and where it is used.
|
|
11
|
+
2. **Flow** — the key path through the code, step by step.
|
|
12
|
+
3. **Edge cases & failure modes** — inputs or states that need care.
|
|
13
|
+
4. **Risks** — anything surprising, fragile, or easy to break.
|
|
14
|
+
|
|
15
|
+
Quote `file:line` for each claim. Read the code before explaining it; do not guess.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Writes focused, regression-catching tests that match the project's conventions.
|
|
3
|
+
model: sonnet
|
|
4
|
+
---
|
|
5
|
+
You write tests that catch real regressions. Read the target to infer its contract, mirror the
|
|
6
|
+
project's existing test framework and style, and cover the happy path, the key edge cases, and a
|
|
7
|
+
failure case. Keep every test deterministic and independent — no network, no sleeps; use temp dirs and
|
|
8
|
+
fixtures. Prefer a few sharp tests over many shallow ones, and name the file each test should live in.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate focused, runnable tests for a target file or function.
|
|
3
|
+
---
|
|
4
|
+
Write tests for: $ARGUMENTS
|
|
5
|
+
|
|
6
|
+
1. Read the target and infer its contract — inputs, outputs, error paths, and invariants.
|
|
7
|
+
2. Match the project's existing test framework and conventions (look at the nearest tests first).
|
|
8
|
+
3. Cover the happy path, the important edge cases, and at least one failure/error case.
|
|
9
|
+
4. Make every test deterministic and independent — no network, no sleeps; use fixtures and temp dirs.
|
|
10
|
+
5. Output runnable test code, and name the file it should live in.
|
|
11
|
+
|
|
12
|
+
Prefer a few sharp tests that would actually catch a regression over many shallow ones.
|
javis/caching.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Optional prompt-cache markers (provider-agnostic via litellm).
|
|
2
|
+
|
|
3
|
+
When enabled, marks the stable prefix (the system message) with a `cache_control` breakpoint.
|
|
4
|
+
litellm applies it for providers that support explicit prompt caching (Anthropic, Bedrock,
|
|
5
|
+
DeepSeek, …) and ignores it elsewhere — JAVIS never branches on provider. Off by default;
|
|
6
|
+
opt in (`--cache`) only when your tier's provider benefits. Non-mutating: returns a new list.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
_BREAKPOINT = {"type": "ephemeral"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _as_cached_blocks(content):
|
|
15
|
+
if isinstance(content, str):
|
|
16
|
+
return [{"type": "text", "text": content, "cache_control": _BREAKPOINT}]
|
|
17
|
+
if isinstance(content, list):
|
|
18
|
+
blocks = [dict(b) if isinstance(b, dict) else b for b in content]
|
|
19
|
+
for block in reversed(blocks):
|
|
20
|
+
if isinstance(block, dict) and block.get("type") == "text":
|
|
21
|
+
block["cache_control"] = _BREAKPOINT
|
|
22
|
+
break
|
|
23
|
+
return blocks
|
|
24
|
+
return content
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def apply_cache_control(messages: list[dict]) -> list[dict]:
|
|
28
|
+
"""Return messages with a cache_control breakpoint on the first system message."""
|
|
29
|
+
out: list[dict] = []
|
|
30
|
+
marked = False
|
|
31
|
+
for msg in messages:
|
|
32
|
+
if not marked and msg.get("role") == "system":
|
|
33
|
+
new = dict(msg)
|
|
34
|
+
new["content"] = _as_cached_blocks(msg.get("content"))
|
|
35
|
+
out.append(new)
|
|
36
|
+
marked = True
|
|
37
|
+
else:
|
|
38
|
+
out.append(msg)
|
|
39
|
+
return out
|
javis/catalog.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""OpenRouter model catalog — pick tool-capable / cheap models instead of guessing slugs.
|
|
2
|
+
|
|
3
|
+
The OpenRouter models API lists every model with its `supported_parameters` and pricing. We
|
|
4
|
+
fetch it best-effort (cached to a file) and expose pure filters, so we stop guessing slugs (we
|
|
5
|
+
hit 'no endpoints found' / 'no tool use' live). OpenRouter-specific by design — it's our routing
|
|
6
|
+
layer, not provider lock-in.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import os
|
|
13
|
+
import tempfile
|
|
14
|
+
import time
|
|
15
|
+
import urllib.request
|
|
16
|
+
|
|
17
|
+
CATALOG_URL = "https://openrouter.ai/api/v1/models"
|
|
18
|
+
_CACHE = os.path.join(tempfile.gettempdir(), "javis_models.json")
|
|
19
|
+
_TTL = 86400 # 1 day
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def fetch_catalog(force: bool = False) -> list[dict]:
|
|
23
|
+
"""Return the OpenRouter model list (cached for a day). Best-effort; needs network."""
|
|
24
|
+
if not force and os.path.isfile(_CACHE) and (time.time() - os.path.getmtime(_CACHE)) < _TTL:
|
|
25
|
+
try:
|
|
26
|
+
with open(_CACHE) as f:
|
|
27
|
+
return json.load(f)
|
|
28
|
+
except (OSError, json.JSONDecodeError):
|
|
29
|
+
pass
|
|
30
|
+
req = urllib.request.Request(CATALOG_URL, headers={"User-Agent": "javis"})
|
|
31
|
+
with urllib.request.urlopen(req, timeout=20) as resp:
|
|
32
|
+
data = json.load(resp)["data"]
|
|
33
|
+
try:
|
|
34
|
+
with open(_CACHE, "w") as f:
|
|
35
|
+
json.dump(data, f)
|
|
36
|
+
except OSError:
|
|
37
|
+
pass
|
|
38
|
+
return data
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _price(model: dict) -> float:
|
|
42
|
+
return float((model.get("pricing") or {}).get("prompt") or 0.0)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def tool_capable(models: list[dict]) -> list[dict]:
|
|
46
|
+
return [m for m in models if "tools" in (m.get("supported_parameters") or [])]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def is_tool_capable(model_id: str, models: list[dict]) -> bool:
|
|
50
|
+
mid = model_id.removeprefix("openrouter/")
|
|
51
|
+
return any(
|
|
52
|
+
m.get("id") == mid and "tools" in (m.get("supported_parameters") or []) for m in models
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def cheapest_tool_capable(models: list[dict], n: int = 15) -> list[tuple[float, str]]:
|
|
57
|
+
return sorted((_price(m), m["id"]) for m in tool_capable(models))[:n]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main() -> None:
|
|
61
|
+
models = fetch_catalog()
|
|
62
|
+
print(f"{len(tool_capable(models))} tool-capable of {len(models)} models\n")
|
|
63
|
+
for price, mid in cheapest_tool_capable(models, 20):
|
|
64
|
+
print(f" ${price * 1e6:7.3f}/Mtok openrouter/{mid}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
if __name__ == "__main__":
|
|
68
|
+
main()
|