vamp-cli 0.1.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.
- vamp_cli/__init__.py +0 -0
- vamp_cli/agent/__init__.py +0 -0
- vamp_cli/agent/context_sync.py +72 -0
- vamp_cli/agent/graph.py +159 -0
- vamp_cli/agent/instructions.py +18 -0
- vamp_cli/agent/nodes.py +375 -0
- vamp_cli/agent/roles.py +8 -0
- vamp_cli/agent/runtime/__init__.py +0 -0
- vamp_cli/agent/runtime/runtime.py +133 -0
- vamp_cli/agent/state.py +55 -0
- vamp_cli/agent/status.py +17 -0
- vamp_cli/config/__init__.py +0 -0
- vamp_cli/config/loader.py +152 -0
- vamp_cli/config/schema.py +82 -0
- vamp_cli/llm/__init__.py +0 -0
- vamp_cli/llm/adapter.py +52 -0
- vamp_cli/llm/adapter_registry.py +26 -0
- vamp_cli/llm/debug_callbacks.py +18 -0
- vamp_cli/llm/router.py +247 -0
- vamp_cli/llm/usage.py +170 -0
- vamp_cli/logging_setup/logging_setup.py +37 -0
- vamp_cli/main.py +1023 -0
- vamp_cli/persistence/__init__.py +29 -0
- vamp_cli/persistence/compaction.py +372 -0
- vamp_cli/persistence/emitter.py +371 -0
- vamp_cli/persistence/event_log.py +303 -0
- vamp_cli/persistence/fork.py +81 -0
- vamp_cli/persistence/loader.py +616 -0
- vamp_cli/persistence/transcript.py +160 -0
- vamp_cli/prompts/prompts.py +182 -0
- vamp_cli/sandbox/__init__.py +0 -0
- vamp_cli/sandbox/base.py +22 -0
- vamp_cli/sandbox/config.py +16 -0
- vamp_cli/sandbox/docker.py +293 -0
- vamp_cli/sandbox/manager.py +31 -0
- vamp_cli/sandbox/result.py +14 -0
- vamp_cli/sandbox/terminal.py +151 -0
- vamp_cli/tools/__init__.py +0 -0
- vamp_cli/tools/base.py +44 -0
- vamp_cli/tools/diagnostic.py +120 -0
- vamp_cli/tools/execute_cmd.py +16 -0
- vamp_cli/tools/files.py +652 -0
- vamp_cli/tools/registry.py +163 -0
- vamp_cli/tools/tools_classes.py +622 -0
- vamp_cli/utils/__init__.py +0 -0
- vamp_cli/utils/error_codes.py +7 -0
- vamp_cli/utils/ignore.py +36 -0
- vamp_cli/utils/sha_256.py +32 -0
- vamp_cli/utils/token_tracker.py +31 -0
- vamp_cli/workspace/__init__.py +0 -0
- vamp_cli/workspace/workspace.py +16 -0
- vamp_cli-0.1.0.dist-info/METADATA +317 -0
- vamp_cli-0.1.0.dist-info/RECORD +57 -0
- vamp_cli-0.1.0.dist-info/WHEEL +5 -0
- vamp_cli-0.1.0.dist-info/entry_points.txt +2 -0
- vamp_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- vamp_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""SHA-256 hash utility for converting strings to hashes."""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def hash_string(input_string: str) -> str:
|
|
7
|
+
"""
|
|
8
|
+
Convert a string to its SHA-256 hash representation.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
input_string: The string to hash.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
A hexadecimal string representing the SHA-256 hash.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
>>> hash_string("hello")
|
|
18
|
+
'2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
|
|
19
|
+
"""
|
|
20
|
+
if not isinstance(input_string, str):
|
|
21
|
+
raise TypeError("Input must be a string")
|
|
22
|
+
|
|
23
|
+
# Encode the string to bytes and compute SHA-256 hash
|
|
24
|
+
hash_object = hashlib.sha256(input_string.encode('utf-8'))
|
|
25
|
+
return hash_object.hexdigest()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if __name__ == "__main__":
|
|
29
|
+
# Test with example
|
|
30
|
+
test_input = "hello"
|
|
31
|
+
result = hash_string(test_input)
|
|
32
|
+
print(f"SHA-256 hash of '{test_input}': {result}")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class Token_Tracker:
|
|
2
|
+
def __init__(self):
|
|
3
|
+
self.usage = {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
|
|
4
|
+
self.open = False
|
|
5
|
+
|
|
6
|
+
def start(self):
|
|
7
|
+
"""Begin a new user turn."""
|
|
8
|
+
self.usage = {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
|
|
9
|
+
self.open = True
|
|
10
|
+
|
|
11
|
+
def add(self, delta):
|
|
12
|
+
if not delta:
|
|
13
|
+
return
|
|
14
|
+
for k in self.usage:
|
|
15
|
+
self.usage[k] += delta.get(k, 0)
|
|
16
|
+
|
|
17
|
+
def close(self):
|
|
18
|
+
"""Turn ended (graph reached END with no pending resume)."""
|
|
19
|
+
if not self.open:
|
|
20
|
+
return
|
|
21
|
+
print("Token Usage (this turn):")
|
|
22
|
+
print(f" Input : {self.usage['input_tokens']}")
|
|
23
|
+
print(f" Output: {self.usage['output_tokens']}")
|
|
24
|
+
print(f" Total : {self.usage['total_tokens']}")
|
|
25
|
+
print()
|
|
26
|
+
self.open = False
|
|
27
|
+
|
|
28
|
+
def abort(self):
|
|
29
|
+
"""User cancelled — drop the accumulator without printing."""
|
|
30
|
+
self.usage = {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
|
|
31
|
+
self.open = False
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from vamp_cli.utils.error_codes import Error_codes
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
class Workspace:
|
|
6
|
+
def __init__(self, root: str) -> None:
|
|
7
|
+
self.root = Path(root).resolve()
|
|
8
|
+
|
|
9
|
+
def safe_path(self, target_path: str) -> str | Literal[Error_codes.PATH_SCOPE_ERROR]:
|
|
10
|
+
target = (self.root / target_path).resolve()
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
target.relative_to(self.root)
|
|
14
|
+
return str(target)
|
|
15
|
+
except:
|
|
16
|
+
return Error_codes.PATH_SCOPE_ERROR
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vamp-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI coding agent.
|
|
5
|
+
Author-email: Satyam Kumar <satkr2208@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Satyam Kumar
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/satkr22/vamp-cli
|
|
29
|
+
Project-URL: Repository, https://github.com/satkr22/vamp-cli
|
|
30
|
+
Classifier: Development Status :: 3 - Alpha
|
|
31
|
+
Classifier: Intended Audience :: Developers
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
36
|
+
Requires-Python: >=3.11
|
|
37
|
+
Description-Content-Type: text/markdown
|
|
38
|
+
License-File: LICENSE
|
|
39
|
+
Requires-Dist: pydantic
|
|
40
|
+
Requires-Dist: rich
|
|
41
|
+
Requires-Dist: typer
|
|
42
|
+
Requires-Dist: click
|
|
43
|
+
Requires-Dist: orjson
|
|
44
|
+
Requires-Dist: pytest
|
|
45
|
+
Requires-Dist: pyyaml
|
|
46
|
+
Requires-Dist: pathspec
|
|
47
|
+
Requires-Dist: prompt-toolkit
|
|
48
|
+
Requires-Dist: langchain-core
|
|
49
|
+
Requires-Dist: langgraph
|
|
50
|
+
Requires-Dist: langchain-litellm
|
|
51
|
+
Requires-Dist: langgraph-checkpoint-sqlite
|
|
52
|
+
Requires-Dist: aiosqlite
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
# VAMP-CLI
|
|
56
|
+
|
|
57
|
+
VAMP-CLI is an interactive coding agent for working in a local repository. It combines a planner, a coder, model fallbacks, workspace-aware file tools, and a Docker-backed command sandbox in one terminal application.
|
|
58
|
+
|
|
59
|
+
The agent can inspect and edit files, search a codebase, run commands, maintain a task list, and ask for confirmation before executing potentially dangerous operations.
|
|
60
|
+
|
|
61
|
+
> **Status:** VAMP-CLI is an early-stage project. The interfaces and default model configuration may change.
|
|
62
|
+
|
|
63
|
+
## Highlights
|
|
64
|
+
|
|
65
|
+
- Interactive terminal UI launched with the `vamp` command.
|
|
66
|
+
- Two operating modes:
|
|
67
|
+
- **Normal mode**: work directly with the coding agent.
|
|
68
|
+
- **Plan mode**: have the planner produce a plan and approve it before implementation.
|
|
69
|
+
- Workspace-scoped file operations and searches.
|
|
70
|
+
- Docker sandbox for command execution, with CPU, memory, process, timeout, and workspace-boundary limits.
|
|
71
|
+
- Human-in-the-loop approval for plan execution and commands classified as dangerous.
|
|
72
|
+
- Configurable models, profiles, prompts, streaming, reasoning, and model fallbacks.
|
|
73
|
+
- Token usage tracking and LangGraph-based agent orchestration.
|
|
74
|
+
- **Session persistence**: all conversations are durably logged as append-only JSONL with per-session SQLite checkpoints.
|
|
75
|
+
- **Session resumption**: resume any past session exactly where it left off, including parked interrupts.
|
|
76
|
+
- **Session listing**: list all past sessions with timestamps and first-message previews.
|
|
77
|
+
- **Forking**: rewind to any past user message and branch off a new conversation path without deleting the original.
|
|
78
|
+
- **Branch switching**: view and switch between conversation branches within a session.
|
|
79
|
+
- **Conversation compaction**: automatically or manually summarize early turns to stay within model context limits.
|
|
80
|
+
|
|
81
|
+
## Requirements
|
|
82
|
+
|
|
83
|
+
- Python 3.11 or newer
|
|
84
|
+
- Docker Engine or Docker Desktop, running and accessible to the current user
|
|
85
|
+
- An API key for each model configured in `src/vamp_cli/config/config.yaml`
|
|
86
|
+
|
|
87
|
+
The first run automatically builds the `vamp-sandbox:latest` image from [`src/vamp_cli/sandbox/Dockerfile`](src/vamp_cli/sandbox/Dockerfile) when it is not already available locally. The image includes Python, Node.js, Git, `ripgrep`, `fd`, and common build tools.
|
|
88
|
+
|
|
89
|
+
## Installation
|
|
90
|
+
|
|
91
|
+
Create and activate a virtual environment, then install the project (all dependencies will be installed itself):
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
python3 -m venv .venv
|
|
95
|
+
source .venv/bin/activate
|
|
96
|
+
python -m pip install --upgrade pip
|
|
97
|
+
python -m pip install -e .
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Confirm that Docker is available before starting the agent:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
docker info
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Configuration
|
|
107
|
+
|
|
108
|
+
Model and profile configuration lives in [`src/vamp_cli/config/config.yaml`](src/vamp_cli/config/config.yaml). API keys are read from environment variables named by each model's `api_key_env` field; keys are not read from YAML values directly.
|
|
109
|
+
|
|
110
|
+
The checked-in default configuration defines `qwen` and `openai`, so both variables must be present unless you edit the configuration to remove or replace one of those models:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
export DASHSCOPE_API_KEY="your-dashscope-key"
|
|
114
|
+
export OPENAI_API_KEY="your-openai-key"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
For a different provider, update the model's `model`, optional `api_base`, `api_key_env`, parameters, capabilities, and fallback list in the YAML file. Profiles select the model and the tools available to the planner or coder.
|
|
118
|
+
|
|
119
|
+
## Running VAMP-CLI
|
|
120
|
+
|
|
121
|
+
Run it from the repository you want the agent to work on:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
vamp
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The current directory becomes the agent workspace and is mounted at `/workspace` inside the sandbox. On startup, VAMP-CLI prints an interactive prompt:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
You:
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### CLI Arguments
|
|
134
|
+
|
|
135
|
+
| Argument | Action |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `--resume <id>` or `-r <id>` | Resume a previous session by its ID |
|
|
138
|
+
| `--list` or `-l` | List all past sessions |
|
|
139
|
+
|
|
140
|
+
Examples:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# List all past sessions
|
|
144
|
+
vamp --list
|
|
145
|
+
|
|
146
|
+
# Resume a specific session
|
|
147
|
+
vamp --resume 01a145b4-5103-7014-97da-d5ca9c871d68
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### In-Session Commands
|
|
151
|
+
|
|
152
|
+
| Command | Action |
|
|
153
|
+
| --- | --- |
|
|
154
|
+
| `/mode` | Select `plan` or `normal` mode |
|
|
155
|
+
| `/exit` | Stop the session and remove the active sandbox container |
|
|
156
|
+
| `/quit` | Same as `/exit` |
|
|
157
|
+
| `/fork` | Rewind to a previous user message and create a new branch |
|
|
158
|
+
| `/fork <N>` | Fork directly to before message N (non-interactive) |
|
|
159
|
+
| `/branches` | View all branches in the current session and switch between them |
|
|
160
|
+
| `/compact` | Summarize early conversation turns to reduce context usage |
|
|
161
|
+
| `/compact <N>` | Compact keeping the last N turns intact (default: 4) |
|
|
162
|
+
| `/config` | Change configurations of models, coder or planner profiles, and tool access. |
|
|
163
|
+
|
|
164
|
+
When the agent requests approval, answer `yes` to continue or `no` and provide a reason to deny the action. Approvals are used for plan implementation and security-sensitive tool calls such as destructive commands, package installation, or network access.
|
|
165
|
+
|
|
166
|
+
Example requests:
|
|
167
|
+
|
|
168
|
+
```text
|
|
169
|
+
Inspect this repository and explain how the authentication flow works.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
/mode
|
|
174
|
+
Select Mode [plan/normal]: plan
|
|
175
|
+
Add tests for the configuration loader, then implement the changes after I approve the plan.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Session Persistence & Resumption
|
|
179
|
+
|
|
180
|
+
VAMP-CLI automatically saves every interaction so you can pick up where you left off.
|
|
181
|
+
|
|
182
|
+
### How Sessions Are Stored
|
|
183
|
+
|
|
184
|
+
Sessions are persisted in `~/.vamp/` using two complementary mechanisms:
|
|
185
|
+
|
|
186
|
+
| Storage | Location | Contents |
|
|
187
|
+
| --- | --- | --- |
|
|
188
|
+
| **JSONL Event Log** | `~/.vamp/sessions/<id>.jsonl` | Append-only, human-readable record of every event (messages, tool calls, mode switches, interrupts, forks, compactions). Each event has a UUID7, parent UUID, and timestamp. |
|
|
189
|
+
| **Head Sidecar** | `~/.vamp/sessions/<id>.head` | Contains the UUID of the current leaf (tip) of the active branch. |
|
|
190
|
+
| **SQLite Checkpoint** | `~/.vamp/checkpoints/<id>.sqlite` | LangGraph's internal graph state — full message objects, plan, todo list, iteration count, and pipeline flags. |
|
|
191
|
+
|
|
192
|
+
### Resuming a Session
|
|
193
|
+
|
|
194
|
+
When you resume a session with `vamp --resume <id>`, VAMP-CLI:
|
|
195
|
+
|
|
196
|
+
1. **Loads the event chain** — walks the `parentUuid` linked list from the current leaf back to `session_start`, reconstructing the full conversation history.
|
|
197
|
+
2. **Recovers CLI state** — replays the events to determine the current mode, whether the session had started, and whether a human-in-the-loop interrupt is still pending.
|
|
198
|
+
3. **Restores graph state** — reads the authoritative LangGraph state from the SQLite checkpointer. If the checkpointer is missing or corrupted, it falls back to reconstructing state from the JSONL event log (lossy but functional — preserves messages, reasoning content, plan, and todo list).
|
|
199
|
+
4. **Handles parked interrupts** — if the previous session was interrupted mid-approval (plan approval or dangerous tool verification), the user is immediately prompted to approve or deny before continuing.
|
|
200
|
+
|
|
201
|
+
### Platform-Independent
|
|
202
|
+
|
|
203
|
+
The `~/.vamp` directory is relative to the user's home directory, so sessions work across different projects and can be listed from anywhere — not just the original workspace directory.
|
|
204
|
+
|
|
205
|
+
## Forking & Branching
|
|
206
|
+
|
|
207
|
+
The JSONL event log uses a `parentUuid` chain instead of a linear sequence, which means conversations can branch.
|
|
208
|
+
|
|
209
|
+
### Forking (`/fork`)
|
|
210
|
+
|
|
211
|
+
Forking lets you rewind to any past user message and start a new branch from that point:
|
|
212
|
+
|
|
213
|
+
1. Type `/fork` to see a numbered list of user messages on the current branch.
|
|
214
|
+
2. Choose a message number to rewind to *before* that message.
|
|
215
|
+
3. VAMP-CLI reconstructs the agent state at that point, creates a new LangGraph checkpointer thread, and appends a `fork` event to the JSONL (pointing its `parentUuid` at the fork point).
|
|
216
|
+
4. The old branch is **never deleted** — it remains intact and can be switched back to at any time.
|
|
217
|
+
|
|
218
|
+
Compact (summarized) messages are also forkable. Forking to a compacted message creates a new branch where the original (unsummarized) messages are restored.
|
|
219
|
+
|
|
220
|
+
### Branch Switching (`/branches`)
|
|
221
|
+
|
|
222
|
+
Each fork creates a new branch tip (leaf). Type `/branches` to:
|
|
223
|
+
|
|
224
|
+
- See all branch tips with a short preview of the last user message on each.
|
|
225
|
+
- Identify the current branch (marked with `<- current`).
|
|
226
|
+
- Switch to any branch by number — this repoints the `.head` sidecar, reloads state from the JSONL, and switches the checkpointer thread.
|
|
227
|
+
|
|
228
|
+
## Conversation Compaction
|
|
229
|
+
|
|
230
|
+
Long conversations can exceed the model's context window. Compaction solves this by summarizing early turns.
|
|
231
|
+
|
|
232
|
+
### Manual Compaction (`/compact`)
|
|
233
|
+
|
|
234
|
+
Type `/compact` to summarize all but the last 4 user turns. Use `/compact <N>` to keep a different number of recent turns. The process:
|
|
235
|
+
|
|
236
|
+
1. Identifies the range of events to compact (earliest user messages up to, but not including, the keep boundary).
|
|
237
|
+
2. Builds a transcript from those events.
|
|
238
|
+
3. Calls the current model to produce a dense, information-rich summary.
|
|
239
|
+
4. Appends a `compaction` event to the JSONL (original events are kept — they are "shadowed", not deleted).
|
|
240
|
+
5. Replaces the checkpointer's message channels with the compacted view (summary marker + recent messages only).
|
|
241
|
+
|
|
242
|
+
### Auto-Compaction
|
|
243
|
+
|
|
244
|
+
When the last prompt's input tokens exceed **90%** of the model's context window (configurable via `DEFAULT_COMPACT_THRESHOLD`), VAMP-CLI automatically runs compaction before the next turn. This keeps sessions healthy without manual intervention.
|
|
245
|
+
|
|
246
|
+
A progress line is printed:
|
|
247
|
+
```
|
|
248
|
+
[auto-compact] context at 118,000/128,000 tokens (92.2%) — summarizing…
|
|
249
|
+
[auto-compact] done: 24 events, ~9,500 → ~600 tokens
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## How it works
|
|
253
|
+
|
|
254
|
+
1. `vamp_cli.main` creates a workspace, ignore matcher, tool registry, model router, EventLog, and Docker sandbox.
|
|
255
|
+
2. The selected planner or coder profile supplies a system prompt and permitted tools.
|
|
256
|
+
3. LangGraph routes model output through tool classification, approval, and execution nodes.
|
|
257
|
+
4. File tools operate within the current workspace; terminal commands execute in the mounted Docker container.
|
|
258
|
+
5. An `EventEmitter` translates LangChain `astream_events` v2 frames into durable JSONL events in real time — `on_chat_model_start/stream/end` → `assistant_message`, `on_tool_start/end/error` → `tool_result`.
|
|
259
|
+
6. The session retains graph state via LangGraph's SQLite checkpointer so follow-up prompts can continue the current task.
|
|
260
|
+
7. On resume, the event log and checkpointer are rehydrated together — the event log provides the human-readable chain and fallback state, while the checkpointer is the authoritative source for the LangGraph agent state.
|
|
261
|
+
|
|
262
|
+
The main package areas are:
|
|
263
|
+
|
|
264
|
+
```text
|
|
265
|
+
src/vamp_cli/
|
|
266
|
+
├── agent/ LangGraph state, nodes, routing, and runtime profiles
|
|
267
|
+
├── config/ YAML loading, validation, model/profile configuration
|
|
268
|
+
├── llm/ LiteLLM-backed model routing, adapters, fallbacks, usage
|
|
269
|
+
├── prompts/ Planner and coder system prompts
|
|
270
|
+
├── sandbox/ Docker lifecycle and command execution
|
|
271
|
+
├── tools/ File, search, diagnostic, todo, and command tools
|
|
272
|
+
├── workspace/ Workspace path-safety enforcement
|
|
273
|
+
├── persistence/ Session event log, emitter, loader, fork, compaction, transcript
|
|
274
|
+
└── main.py Interactive CLI entry point
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Persistence Module Details
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
src/vamp_cli/persistence/
|
|
281
|
+
├── event_log.py Append-only JSONL writer with async queue, UUID7, parent-chain, and .head sidecar
|
|
282
|
+
├── emitter.py Translates LangChain astream_events v2 → event log entries
|
|
283
|
+
├── loader.py Session rehydration: load_chain, derive_display_state,
|
|
284
|
+
│ detect_pending_interrupt, reconstruct_agent_state, list_sessions
|
|
285
|
+
├── fork.py Rewind to a past event and seed a new checkpointer thread
|
|
286
|
+
├── compaction.py Summarize early turns, plan ranges, auto-compact on threshold
|
|
287
|
+
└── transcript.py Render and print human-readable session transcripts
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Development and tests
|
|
291
|
+
|
|
292
|
+
Run the automated test suite from the repository root:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
python -m pytest
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Some sandbox and system-verification tests require Docker. The manual security and tool-operation scenarios are documented in [`tests/TEST_VERIFICATION.md`](tests/TEST_VERIFICATION.md).
|
|
299
|
+
|
|
300
|
+
For a quick syntax check:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
python -m compileall src
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Security and operational notes
|
|
307
|
+
|
|
308
|
+
- The host project directory is mounted into the sandbox at `/workspace`.
|
|
309
|
+
- The default sandbox limits are 2 CPUs, 2 GB of memory, 256 processes, and 30 seconds per command.
|
|
310
|
+
- Commands are executed with `/bin/bash -lc` inside the container.
|
|
311
|
+
- The default sandbox has network access; set `network_enabled: false` in the sandbox configuration if an offline container is required.
|
|
312
|
+
- Treat model output as untrusted. Review approval prompts carefully, especially for deletion, package installation, credential access, and network operations.
|
|
313
|
+
- The current graph limits an agent run to 15 iterations to prevent unbounded tool loops.
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
VAMP-CLI is released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
vamp_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
vamp_cli/main.py,sha256=GNPHV2QfnrQrQdxAC7_Ssf5ZX44xI9aDPT2T7WIEilw,44716
|
|
3
|
+
vamp_cli/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
vamp_cli/agent/context_sync.py,sha256=w0S1ATPH5GknMAkI5nNi2ITplvAixsB65vkmpCsXByw,2809
|
|
5
|
+
vamp_cli/agent/graph.py,sha256=e8u0GLLgV0J9gBftbxSbvO28vt-KpQXF2CJZf6Q8KGQ,4242
|
|
6
|
+
vamp_cli/agent/instructions.py,sha256=1ja0nVZ35zV5Xl605rNyv6TnIQP3OWFWOS_8fFKGgaI,895
|
|
7
|
+
vamp_cli/agent/nodes.py,sha256=zoMPobazRPn1UEUVvcsMhJIvflscCSbrEzazO7oqT8o,13660
|
|
8
|
+
vamp_cli/agent/roles.py,sha256=U9Kjk1lpslyRkmWsKU0Ri5jBeL8WlKmfL1aaCcaS82k,158
|
|
9
|
+
vamp_cli/agent/state.py,sha256=F19LHcA2aJCeJ8hbpLAcRbymuYWR52XFlO1sRRk4Hck,1081
|
|
10
|
+
vamp_cli/agent/status.py,sha256=HTNTgmGXRP8_OVgQkkJR7gzlHDtY_kd3f5vPxIchTpY,362
|
|
11
|
+
vamp_cli/agent/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
vamp_cli/agent/runtime/runtime.py,sha256=iDTnCK7vE-2RqC_mV3wS-r7IIcZKnBnRJ7r0WUVcBj8,3781
|
|
13
|
+
vamp_cli/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
vamp_cli/config/loader.py,sha256=hq7ensrxiM94KPfXHhECAaTse3ohWbhE6g2sUxFtpmA,4818
|
|
15
|
+
vamp_cli/config/schema.py,sha256=uLfi5LY3AtvH62YMjYrW-64uI10FowQMXci2_0XzRK4,2745
|
|
16
|
+
vamp_cli/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
vamp_cli/llm/adapter.py,sha256=z0IQAZp3hM3legy-zRsL5Ja5MJQrxK09bgz5OMs7mQA,1293
|
|
18
|
+
vamp_cli/llm/adapter_registry.py,sha256=E5U4qBUyWGRJbKjs9ag_vVC-6z0EqpRQDIWtu4mEfrY,680
|
|
19
|
+
vamp_cli/llm/debug_callbacks.py,sha256=-iPOaPnzS9mH2PVre8fAXVg00uqoFeBcrpJF3zDZIIQ,715
|
|
20
|
+
vamp_cli/llm/router.py,sha256=HDfhS_1VgHx3H9feyIqWy1NdEVsb4rWUTfLIfJx07tk,7835
|
|
21
|
+
vamp_cli/llm/usage.py,sha256=LCoaU9IK1x5BNHBt6Vtt9rxMXRb9uEA2a8X7YITjH2c,5113
|
|
22
|
+
vamp_cli/logging_setup/logging_setup.py,sha256=e2a4yKcpci6oqXSBL-4r--PYfJ_1-D-a1M9CQRA_xRw,1018
|
|
23
|
+
vamp_cli/persistence/__init__.py,sha256=AXP_Ji7DNZJuhE3eGvjUfUtvcGhZPS3Dncgt2FDgTxs,1357
|
|
24
|
+
vamp_cli/persistence/compaction.py,sha256=WYq6prdTszJNwy-Hps0FYYsqeMRJybX6rLvHIWRXrcE,11832
|
|
25
|
+
vamp_cli/persistence/emitter.py,sha256=_Yn0xJTntCot5YRHvp-C1tBtfHaLHoHuoHCVQRwmI4M,13503
|
|
26
|
+
vamp_cli/persistence/event_log.py,sha256=mmVKzHw-WfJEKm2QHbLJUdETVzKYLC3JthsSuRkEWVg,9544
|
|
27
|
+
vamp_cli/persistence/fork.py,sha256=vCnRd5iWfL1xKOyM1rkw-RewFJ-6CqQfT1u9e_tbuQQ,2790
|
|
28
|
+
vamp_cli/persistence/loader.py,sha256=gRLZtpF1Zzdqlfyl4qqf2kG8w5j_vpJ5iLv3KXU0GGU,20470
|
|
29
|
+
vamp_cli/persistence/transcript.py,sha256=sXyv8c0ZmpnmFylW9H8zN8u7qyefamKrs86fij9StiY,4396
|
|
30
|
+
vamp_cli/prompts/prompts.py,sha256=pFCPPT-OnhjOsHmmrRsNk2uOHWFArC-T8K_0WwKfe5o,5815
|
|
31
|
+
vamp_cli/sandbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
32
|
+
vamp_cli/sandbox/base.py,sha256=p3HIF5wIneug7aVROAMXtzmkUiMX-ABuCxm8Q7ntCeI,455
|
|
33
|
+
vamp_cli/sandbox/config.py,sha256=K68UII6SOho8h_vHYvUiSeFvYNuZoaF0jeZRQzs22V8,293
|
|
34
|
+
vamp_cli/sandbox/docker.py,sha256=XWY3rRj6LSHvkkCwt-1_HwdwKm8XcUqddIalK4mPcHM,8861
|
|
35
|
+
vamp_cli/sandbox/manager.py,sha256=kEBozOR1VfNHvMB5VhKD50Vz6A5qOm21xPqLkyIlIu4,801
|
|
36
|
+
vamp_cli/sandbox/result.py,sha256=STjaKrfTomrGqsqjXu3UpTR66iFSg43B5m-SLVz9uYQ,194
|
|
37
|
+
vamp_cli/sandbox/terminal.py,sha256=A7arcsvJ3jFhFsOj923jkZS1_GZXka5dk6HUfCQK_r4,3885
|
|
38
|
+
vamp_cli/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
+
vamp_cli/tools/base.py,sha256=p_BIDcgK96qeE23SnFRgEHby_ronL5ISLSMwmCS7YfQ,1095
|
|
40
|
+
vamp_cli/tools/diagnostic.py,sha256=_mAYVZZNw35qwou5Ta3JG1xe1mtnGUWqmyKcFfHjMQQ,4633
|
|
41
|
+
vamp_cli/tools/execute_cmd.py,sha256=-nvmSma6Ah0v2nFsE5yXy4aDEJXjSseqt7wgRNYSeh0,354
|
|
42
|
+
vamp_cli/tools/files.py,sha256=5H2oDKqN0ZW3gL-bDNUgmTZGaWRsTTzI9dHHg8AFpC0,20117
|
|
43
|
+
vamp_cli/tools/registry.py,sha256=GhPrHsWAwm8sUsozM2QsKj5iFUanpEfQ1F45saRarK8,5855
|
|
44
|
+
vamp_cli/tools/tools_classes.py,sha256=rM6ZmCuZDxNvrn9ntLJYAcPr08glE6VPv4mh4gxrqHQ,26987
|
|
45
|
+
vamp_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
|
+
vamp_cli/utils/error_codes.py,sha256=VVZwP1UT8075VTevwlK3UGmm3j51Avwu07s_XySFzSQ,193
|
|
47
|
+
vamp_cli/utils/ignore.py,sha256=N5a8Pxw0hTOWhUHf4UHWsb2chTGQzYkcMkO6GyCZcGI,958
|
|
48
|
+
vamp_cli/utils/sha_256.py,sha256=Sl1zuXd98LQmH8iJCaLK-ilVHLIal5HJOgRM4PXR3T4,863
|
|
49
|
+
vamp_cli/utils/token_tracker.py,sha256=zVMEm8sDB__XHipDoHZ2O5fLAlC2D6jFaXi2JSK4kO8,1048
|
|
50
|
+
vamp_cli/workspace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
+
vamp_cli/workspace/workspace.py,sha256=KjHo69GEmSqV5ItpTdSskPZ_r8nbuIrWKwGlFBipI_Y,515
|
|
52
|
+
vamp_cli-0.1.0.dist-info/licenses/LICENSE,sha256=3x-ms2yeN5WcGD7t4gSlBe88rRA4MSmLVpIP4JBonow,1069
|
|
53
|
+
vamp_cli-0.1.0.dist-info/METADATA,sha256=hUT4T0YzOfUbmo4b7e66wo1mgLdtBEhdKshSB7ihzdk,15190
|
|
54
|
+
vamp_cli-0.1.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
55
|
+
vamp_cli-0.1.0.dist-info/entry_points.txt,sha256=dcoZlhNwFn3aiyDeumcaQcOC3GLLKJ8eCReL75WFftg,45
|
|
56
|
+
vamp_cli-0.1.0.dist-info/top_level.txt,sha256=SCTgoyWFu2SVOzNr65FGpUjNPqzwRWzqxhbBrItC5D4,9
|
|
57
|
+
vamp_cli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Satyam Kumar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vamp_cli
|