sangam 0.1.6__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.
- sangam-0.1.6/PKG-INFO +494 -0
- sangam-0.1.6/README.md +465 -0
- sangam-0.1.6/sangam/__init__.py +28 -0
- sangam-0.1.6/sangam/cli/__init__.py +5 -0
- sangam-0.1.6/sangam/cli/chat.py +1247 -0
- sangam-0.1.6/sangam/cli/commands/__init__.py +11 -0
- sangam-0.1.6/sangam/cli/commands/agent.py +137 -0
- sangam-0.1.6/sangam/cli/commands/exec.py +149 -0
- sangam-0.1.6/sangam/cli/commands/models.py +224 -0
- sangam-0.1.6/sangam/cli/commands/serve.py +86 -0
- sangam-0.1.6/sangam/cli/interactive.py +754 -0
- sangam-0.1.6/sangam/cli/main.py +382 -0
- sangam-0.1.6/sangam/cli/markdown.py +161 -0
- sangam-0.1.6/sangam/cli/spinner.py +98 -0
- sangam-0.1.6/sangam/config.py +99 -0
- sangam-0.1.6/sangam/core/__init__.py +47 -0
- sangam-0.1.6/sangam/core/agent.py +694 -0
- sangam-0.1.6/sangam/core/engine.py +77 -0
- sangam-0.1.6/sangam/core/memory.py +326 -0
- sangam-0.1.6/sangam/core/model/__init__.py +127 -0
- sangam-0.1.6/sangam/core/model/catalog.py +819 -0
- sangam-0.1.6/sangam/core/model/client.py +175 -0
- sangam-0.1.6/sangam/core/model/local.py +298 -0
- sangam-0.1.6/sangam/core/model/model.py +335 -0
- sangam-0.1.6/sangam/core/planner.py +406 -0
- sangam-0.1.6/sangam/core/runtime/__init__.py +54 -0
- sangam-0.1.6/sangam/core/runtime/base.py +156 -0
- sangam-0.1.6/sangam/core/runtime/container.py +266 -0
- sangam-0.1.6/sangam/core/runtime/detect.py +140 -0
- sangam-0.1.6/sangam/core/runtime/nvm.py +362 -0
- sangam-0.1.6/sangam/core/runtime/registry.py +195 -0
- sangam-0.1.6/sangam/core/runtime/shell.py +253 -0
- sangam-0.1.6/sangam/core/runtime/subprocess.py +157 -0
- sangam-0.1.6/sangam/core/runtime/venv.py +261 -0
- sangam-0.1.6/sangam/core/sandbox.py +326 -0
- sangam-0.1.6/sangam/core/session_store.py +726 -0
- sangam-0.1.6/sangam/core/tools/__init__.py +34 -0
- sangam-0.1.6/sangam/core/tools/agent_tools.py +191 -0
- sangam-0.1.6/sangam/core/tools/exec_tools.py +244 -0
- sangam-0.1.6/sangam/core/tools/file_tools.py +181 -0
- sangam-0.1.6/sangam/core/tools/qa_tools.py +120 -0
- sangam-0.1.6/sangam/core/tools/registry.py +398 -0
- sangam-0.1.6/sangam/core/tools/time_tools.py +81 -0
- sangam-0.1.6/sangam/core/tools/type_check_tools.py +296 -0
- sangam-0.1.6/sangam/file_ops.py +157 -0
- sangam-0.1.6/sangam/logger.py +139 -0
- sangam-0.1.6/sangam/mypy_cli.py +12 -0
- sangam-0.1.6/sangam/sangam_integration.py +264 -0
- sangam-0.1.6/sangam/server/__init__.py +31 -0
- sangam-0.1.6/sangam/server/http_api.py +597 -0
- sangam-0.1.6/sangam/task_engine.py +314 -0
- sangam-0.1.6/sangam.egg-info/PKG-INFO +494 -0
- sangam-0.1.6/sangam.egg-info/SOURCES.txt +87 -0
- sangam-0.1.6/sangam.egg-info/dependency_links.txt +1 -0
- sangam-0.1.6/sangam.egg-info/entry_points.txt +2 -0
- sangam-0.1.6/sangam.egg-info/requires.txt +2 -0
- sangam-0.1.6/sangam.egg-info/top_level.txt +1 -0
- sangam-0.1.6/setup.cfg +4 -0
- sangam-0.1.6/setup.py +41 -0
- sangam-0.1.6/tests/test_agent.py +439 -0
- sangam-0.1.6/tests/test_agent_tools.py +255 -0
- sangam-0.1.6/tests/test_cli_exec.py +138 -0
- sangam-0.1.6/tests/test_cli_interactive.py +1808 -0
- sangam-0.1.6/tests/test_cli_serve.py +100 -0
- sangam-0.1.6/tests/test_config.py +113 -0
- sangam-0.1.6/tests/test_file_ops.py +129 -0
- sangam-0.1.6/tests/test_install_sh.py +326 -0
- sangam-0.1.6/tests/test_interactive_prompts.py +529 -0
- sangam-0.1.6/tests/test_logger.py +62 -0
- sangam-0.1.6/tests/test_memory.py +238 -0
- sangam-0.1.6/tests/test_model_catalog.py +629 -0
- sangam-0.1.6/tests/test_model_client.py +508 -0
- sangam-0.1.6/tests/test_planner.py +244 -0
- sangam-0.1.6/tests/test_runtime_base.py +117 -0
- sangam-0.1.6/tests/test_runtime_container.py +170 -0
- sangam-0.1.6/tests/test_runtime_detect.py +101 -0
- sangam-0.1.6/tests/test_runtime_nvm.py +190 -0
- sangam-0.1.6/tests/test_runtime_registry.py +190 -0
- sangam-0.1.6/tests/test_runtime_shell.py +130 -0
- sangam-0.1.6/tests/test_runtime_subprocess.py +125 -0
- sangam-0.1.6/tests/test_runtime_venv.py +144 -0
- sangam-0.1.6/tests/test_sandbox.py +224 -0
- sangam-0.1.6/tests/test_sangam_integration.py +250 -0
- sangam-0.1.6/tests/test_server_http_api.py +243 -0
- sangam-0.1.6/tests/test_session_store.py +285 -0
- sangam-0.1.6/tests/test_spinner.py +140 -0
- sangam-0.1.6/tests/test_task_engine.py +109 -0
- sangam-0.1.6/tests/test_tools.py +1019 -0
- sangam-0.1.6/tests/test_vscode_extension.py +110 -0
sangam-0.1.6/PKG-INFO
ADDED
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sangam
|
|
3
|
+
Version: 0.1.6
|
|
4
|
+
Summary: Intelligent type-checking based code analysis and generation CLI tool
|
|
5
|
+
Author: sangam team
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
16
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: mypy>=0.900
|
|
20
|
+
Requires-Dist: flask>=2.0
|
|
21
|
+
Dynamic: author
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: license
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: requires-python
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# sangam
|
|
31
|
+
|
|
32
|
+
> An **LLM harness** — a runtime and orchestration framework for coding agents
|
|
33
|
+
> backed by large language models.
|
|
34
|
+
|
|
35
|
+
`sangam` is being built as an **LLM harness**: a runtime that hosts
|
|
36
|
+
LLM-driven coding agents, gives them isolated places to run code, and a typed set
|
|
37
|
+
of tools to call. The design rests on four pieces —
|
|
38
|
+
|
|
39
|
+
- **Runtime-agnostic execution** — a single `Executor` interface
|
|
40
|
+
(`RunSpec` in, `RunResult` out) with pluggable backends (Python venv, Node/nvm,
|
|
41
|
+
Docker/Podman, subprocess) so the agent never depends on a specific runtime.
|
|
42
|
+
- **Typed tool registry** — each tool (read/write/edit files, run code,
|
|
43
|
+
type-check, run tests, search) exposes a JSON schema, letting the LLM act
|
|
44
|
+
through function-calling.
|
|
45
|
+
- **Model client** — an LLM abstraction (`complete` / `chat` / `tools`) that can
|
|
46
|
+
talk to any provider: any OpenAI-compatible endpoint, or local models (Ollama /
|
|
47
|
+
LM Studio). When no API key is set it falls back to a local model automatically.
|
|
48
|
+
- **Agent loop** — plan → act (call a tool) → observe (tests/lint/output) →
|
|
49
|
+
reflect, with conversation memory and resumable state.
|
|
50
|
+
|
|
51
|
+
It started as a mypy-focused natural-language CLI, and those capabilities — mypy
|
|
52
|
+
type analysis, file operations, and resumable task history — stay on as a
|
|
53
|
+
built-in toolset and a working surface. Full architecture in
|
|
54
|
+
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
55
|
+
|
|
56
|
+
## Status
|
|
57
|
+
|
|
58
|
+
The harness is under active construction: the core agent loop, multi-runtime
|
|
59
|
+
executors, tool registry, model client, session store, headless HTTP API server,
|
|
60
|
+
and VS Code extension are in place (Phases 1–4 complete). The local webapp and
|
|
61
|
+
desktop app surfaces are the remaining roadmap. See [`todo.md`](todo.md) for the
|
|
62
|
+
roadmap.
|
|
63
|
+
|
|
64
|
+
**Available now**
|
|
65
|
+
|
|
66
|
+
- Core engine split from the CLI surface (`core/engine.py`) — usable as a library.
|
|
67
|
+
- `Executor` protocol + `RunSpec` / `RunResult` runtime contracts
|
|
68
|
+
(`core/runtime/base.py`).
|
|
69
|
+
- **Multi-runtime executors** — pluggable backends behind the single `Executor`
|
|
70
|
+
interface:
|
|
71
|
+
- `VenvExecutor` (`core/runtime/venv.py`) — creates an isolated venv, installs
|
|
72
|
+
deps via pip, runs Python, captures stdout/stderr/exit.
|
|
73
|
+
- `NvmExecutor` (`core/runtime/nvm.py`) — runs JS/React via nvm + npm
|
|
74
|
+
(`nvm use`, `npm install`, run/build).
|
|
75
|
+
- `ShellExecutor` (`core/runtime/shell.py`) — runs native bash/zsh scripts and
|
|
76
|
+
one-off commands, auto-detecting the user's shell.
|
|
77
|
+
- `ContainerExecutor` (`core/runtime/container.py`) — runs arbitrary code in
|
|
78
|
+
Docker or Podman (image pull, run).
|
|
79
|
+
- `SubprocessExecutor` (`core/runtime/subprocess.py`) — plain subprocess
|
|
80
|
+
fallback backend.
|
|
81
|
+
- **Runtime auto-detection** (`core/runtime/detect.py`) — maps a runtime name
|
|
82
|
+
(`python`/`venv`, `node`/`js`/`react`/`npm`, `shell`/`bash`/`zsh`,
|
|
83
|
+
`container`/`docker`/`podman`, `subprocess`/`direct`) to the matching backend.
|
|
84
|
+
- **Environment registry** (`core/runtime/registry.py`) — records created venvs
|
|
85
|
+
and npm projects in `~/.sangam/environments.json` so they are reused across
|
|
86
|
+
runs instead of recreated.
|
|
87
|
+
- **Sandbox Manager** (`core/sandbox.py`) — `SandboxPolicy` + `SandboxedExecutor`
|
|
88
|
+
wrapping any backend with filesystem scope (path-level validation, symlink
|
|
89
|
+
resolution), wall-clock timeouts (default/max clamping), network isolation
|
|
90
|
+
(proxy-env clearing), and POSIX resource limits (`cpu_time`, `fsize`,
|
|
91
|
+
`nofile`) via `resource_limit_preexec`.
|
|
92
|
+
- **Agent loop** — `Agent` (`core/agent.py`) orchestrating `Planner`
|
|
93
|
+
(`core/planner.py`), `Memory` (`core/memory.py`), the `ToolRegistry`, and an
|
|
94
|
+
optional `ModelClient` in a plan → act → observe → reflect loop. Runs in a
|
|
95
|
+
deterministic mode when no model client is configured.
|
|
96
|
+
- **Model client** (`core/model/`) — `ModelClient` protocol with
|
|
97
|
+
`OpenAIModelClient` (any OpenAI-compatible endpoint) and `LocalModelClient`
|
|
98
|
+
(local providers such as Ollama / LM Studio); credentials read from env/config.
|
|
99
|
+
`build_model_client(config)` picks the backend — the entry selected from the
|
|
100
|
+
model catalog when one is configured, otherwise OpenAI when an API key is set,
|
|
101
|
+
otherwise a local model (auto-detecting an available model from the running
|
|
102
|
+
server when `MODEL_NAME` is unset).
|
|
103
|
+
- **Model catalog** (`core/model/catalog.py`) — `~/.sangam/models.yaml` is the
|
|
104
|
+
source of truth for which models sangam can use, following Continue's
|
|
105
|
+
`config.yaml` `models` shape (`name`, `provider`, `model`, optional `apiBase` /
|
|
106
|
+
`apiKey` / `roles` / `capabilities` / `defaultCompletionOptions` /
|
|
107
|
+
`requestOptions`). The active chat/agent model is the file's `default` entry,
|
|
108
|
+
else the first entry with role `chat`, else the first entry. `sangam models`
|
|
109
|
+
lists the configured entries merged with the ids advertised by probed local
|
|
110
|
+
runtimes (Ollama, LM Studio, and every configured `apiBase`) via `/v1/models`.
|
|
111
|
+
sangam never installs a model runtime.
|
|
112
|
+
- **Typed tool registry** (`core/tools/`) — `read_file`, `write_file`,
|
|
113
|
+
`edit_file`, `list_files`, `search`, `run_python`, `run_js`, `run_container`,
|
|
114
|
+
`run_shell`, `install_deps`, `type_check`, `run_tests`, `suggest_fixes`, each
|
|
115
|
+
with a JSON schema for LLM function-calling.
|
|
116
|
+
- **Session store** (`core/session_store.py`) — SQLite-backed sessions, messages,
|
|
117
|
+
model/token usage, and FTS5 search (`~/.sangam/sessions.db` by default).
|
|
118
|
+
- **CLI subcommands** — `sangam agent "<goal>"`, `sangam models`,
|
|
119
|
+
`sangam exec --runtime <rt> <command>`, and `sangam serve` (headless HTTP API
|
|
120
|
+
server), plus the legacy single-task positional, REPL, and batch mode.
|
|
121
|
+
- **Headless HTTP API server** (`sangam/server/`, Flask) — exposes the agent,
|
|
122
|
+
tools, runtimes, and session store over local HTTP with SSE streaming; the
|
|
123
|
+
single backend for the VS Code extension, local webapp, and desktop app.
|
|
124
|
+
- **`install.sh`** — pulls sangam from GitHub `main`, installs it into a venv at
|
|
125
|
+
`~/.sangam/venv`, and runs the headless server. Before starting it probes for a
|
|
126
|
+
local model runtime (Ollama / LM Studio); if none is reachable it errors out
|
|
127
|
+
with "no model available/selected" rather than installing one.
|
|
128
|
+
- mypy integration wired through the Executor backends — analyze a file or a
|
|
129
|
+
whole directory, JSON output parsing, and fix suggestions. Defaults to
|
|
130
|
+
`SubprocessExecutor` (`sys.executable -m mypy`); opt-in `use_venv=True` →
|
|
131
|
+
`VenvExecutor` with mypy installed; custom backend via `executor=`.
|
|
132
|
+
- Regex-based task engine — natural-language commands mapped to file operations
|
|
133
|
+
and mypy analysis.
|
|
134
|
+
- File operations — read, write, append, delete, list, and extract
|
|
135
|
+
functions/classes/imports.
|
|
136
|
+
- JSONL task history with search.
|
|
137
|
+
- Interactive REPL and batch mode.
|
|
138
|
+
|
|
139
|
+
**Roadmap**
|
|
140
|
+
|
|
141
|
+
- VS Code extension polish — chat panel, diagnostics, inline actions (extension
|
|
142
|
+
scaffolded and installable; UI activation pending a reload).
|
|
143
|
+
- Local webapp — a single self-contained `index.html` (no build step) served on
|
|
144
|
+
localhost via Python (`sangam web`), talking to the headless server over HTTP.
|
|
145
|
+
- Cross-platform desktop app — React UI over the Python core behind a native
|
|
146
|
+
shell, packaged for macOS (`.app`/`.dmg`) and Windows (`.exe`/`.msi`); reuses
|
|
147
|
+
the headless server as its backend.
|
|
148
|
+
- Hardening — `doctor` capability probing, resumable `history`, runtime/model/
|
|
149
|
+
sandbox config, end-to-end sandbox limits, CI-ready non-interactive mode.
|
|
150
|
+
|
|
151
|
+
## Local Webapp — Roadmap
|
|
152
|
+
|
|
153
|
+
A **single-page webapp** is a zero-install surface for the same harness: one
|
|
154
|
+
self-contained `index.html` (inline HTML + CSS + JS, no build step) served on
|
|
155
|
+
localhost by a small Python static server and talking to the core over HTTP. It
|
|
156
|
+
reuses the headless HTTPS API server from Phase 4 as its backend — another thin
|
|
157
|
+
surface over the same core, not a separate engine.
|
|
158
|
+
|
|
159
|
+
- **`webapp/index.html`** — the app shell (chat panel, file tree, diagnostics,
|
|
160
|
+
agent-step viewer, command palette, status bar) with an inline fetch-based
|
|
161
|
+
client to the core `serve` endpoint.
|
|
162
|
+
- **`sangam web`** — starts the headless server and serves `index.html` on
|
|
163
|
+
localhost via Python's stdlib `http.server` (no extra deps); opens the default
|
|
164
|
+
browser.
|
|
165
|
+
|
|
166
|
+
Full task breakdown in [`todo.md`](todo.md), Phase 6.
|
|
167
|
+
|
|
168
|
+
## Desktop App — Roadmap
|
|
169
|
+
|
|
170
|
+
A **cross-platform native desktop app** (macOS + Windows) is a target surface for
|
|
171
|
+
the same harness. It keeps the existing **Python core** as the engine and adds a
|
|
172
|
+
**React** UI on top — the same "core is a library, surfaces are thin" split used
|
|
173
|
+
for the CLI and the VS Code extension:
|
|
174
|
+
|
|
175
|
+
- **Python core** — the `sangam` package, frozen into a standalone per-OS
|
|
176
|
+
binary and run headless (`sangam serve`, the same HTTPS API server the VS
|
|
177
|
+
Code extension talks to). All agent/tool/runtime logic stays in Python.
|
|
178
|
+
- **React UI** — a TypeScript + React frontend (chat panel, file tree,
|
|
179
|
+
diagnostics, agent-step viewer, command palette) that speaks HTTPS to the
|
|
180
|
+
core over localhost (optionally with TLS/cert configuration) — the same
|
|
181
|
+
wire protocol as the VS Code extension.
|
|
182
|
+
- **Native shell** — a desktop wrapper that bundles the React build and spawns
|
|
183
|
+
the frozen Python core as a sidecar process. Ships a native `.app`/`.dmg` on
|
|
184
|
+
macOS and `.exe`/`.msi` on Windows (Tauri preferred for the OS-webview native
|
|
185
|
+
feel and small binary; Electron as a fallback).
|
|
186
|
+
|
|
187
|
+
Planned packaging steps (full task breakdown in [`todo.md`](todo.md), Phase 7):
|
|
188
|
+
|
|
189
|
+
1. **React UI** — scaffold `desktop-ui/` (Vite + TypeScript + React); build the
|
|
190
|
+
app shell and a typed HTTPS client to the core server.
|
|
191
|
+
2. **Native shell** — scaffold `desktop-app/` (Tauri or Electron); configure it
|
|
192
|
+
to bundle and spawn the frozen Python core sidecar; wire frontend↔core IPC over
|
|
193
|
+
localhost HTTPS.
|
|
194
|
+
3. **Python core packaging** — freeze the core with PyInstaller/Nuitka per OS
|
|
195
|
+
(including mypy + deps); confirm the headless `serve` entry point runs the
|
|
196
|
+
agent loop end-to-end.
|
|
197
|
+
4. **macOS build** — universal `.app` (arm64 + x86_64), `.dmg` installer,
|
|
198
|
+
Developer ID code signing, Apple notarization + stapling, clean-launch test.
|
|
199
|
+
5. **Windows build** — `.exe` + `.msi` installer (WiX/Tauri), WebView2 runtime
|
|
200
|
+
handling, code signing, clean-launch test.
|
|
201
|
+
6. **Release CI** — GitHub Actions matrix (macOS arm64/x86_64, Windows x64):
|
|
202
|
+
build → sign → notarize (macOS) → package → attach to GitHub Releases.
|
|
203
|
+
7. **Updates & polish** — auto-update, native menus/tray, first-run onboarding
|
|
204
|
+
(LLM creds + runtime detection), native window-state persistence.
|
|
205
|
+
|
|
206
|
+
This builds on the headless HTTPS API server from Phase 4 — the desktop app is
|
|
207
|
+
another thin surface over the same server, not a separate backend.
|
|
208
|
+
|
|
209
|
+
## Installation
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pip install -e .
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Requires Python >= 3.9 and `mypy>=0.900` (installed automatically).
|
|
216
|
+
|
|
217
|
+
### Headless server install (`install.sh`)
|
|
218
|
+
|
|
219
|
+
To install sangam and run it as a headless HTTP API server (the backend for the
|
|
220
|
+
VS Code extension, local webapp, and desktop app), use `install.sh`:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
./install.sh # install (or update) and run the server
|
|
224
|
+
./install.sh --install-only # install/update but do not start the server
|
|
225
|
+
./install.sh --port 8765 # bind a specific port (default 8765)
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
`install.sh` pulls the source from GitHub `main`, creates a venv at
|
|
229
|
+
`~/.sangam/venv`, installs the package, and runs `sangam serve`. The server
|
|
230
|
+
needs a model to drive the agent, so before starting it `install.sh` **probes
|
|
231
|
+
for a local model runtime**:
|
|
232
|
+
|
|
233
|
+
- It queries the OpenAI-compatible `/v1/models` endpoint of **Ollama**
|
|
234
|
+
(`127.0.0.1:11434`) and then **LM Studio** (`127.0.0.1:1234`).
|
|
235
|
+
- If a reachable endpoint advertises a model, the server is started using that
|
|
236
|
+
local model.
|
|
237
|
+
- **sangam never installs a model runtime.** If no Ollama or LM Studio endpoint
|
|
238
|
+
is reachable, `install.sh` errors out with **"no model available/selected"**
|
|
239
|
+
and exits without starting the server.
|
|
240
|
+
|
|
241
|
+
Override the probe with environment variables:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
SANGAM_MODEL_ENDPOINT=http://127.0.0.1:12345 SANGAM_MODEL_NAME=bonsai-27b-mlx ./install.sh
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
`--install-only` installs without requiring a model.
|
|
248
|
+
|
|
249
|
+
## Usage
|
|
250
|
+
|
|
251
|
+
### CLI
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Run a single task
|
|
255
|
+
sangam "read main.py"
|
|
256
|
+
|
|
257
|
+
# Interactive mode
|
|
258
|
+
sangam --interactive
|
|
259
|
+
|
|
260
|
+
# Batch mode (from a file)
|
|
261
|
+
sangam --batch tasks.txt
|
|
262
|
+
|
|
263
|
+
# Verbose output
|
|
264
|
+
sangam --verbose "type check src/"
|
|
265
|
+
|
|
266
|
+
# Run the coding agent on a goal
|
|
267
|
+
sangam agent "fix the type errors in src/ and run the tests"
|
|
268
|
+
|
|
269
|
+
# List the models sangam can use (configured + discovered)
|
|
270
|
+
sangam models
|
|
271
|
+
sangam models --no-probe # configured models only (no network)
|
|
272
|
+
sangam models --json # machine-readable listing
|
|
273
|
+
sangam models --select fast-local # show the client for a named entry
|
|
274
|
+
|
|
275
|
+
# Run a command in a chosen runtime
|
|
276
|
+
sangam exec --runtime python "print('hello')"
|
|
277
|
+
sangam exec --runtime node "console.log('hello')"
|
|
278
|
+
sangam exec --runtime shell "ls -la"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Model catalog (`~/.sangam/models.yaml`)
|
|
282
|
+
|
|
283
|
+
`~/.sangam/models.yaml` is the source of truth for which models sangam can use.
|
|
284
|
+
It follows Continue's `config.yaml` `models` shape:
|
|
285
|
+
|
|
286
|
+
```yaml
|
|
287
|
+
default: fast-local # optional: the active chat/agent model
|
|
288
|
+
|
|
289
|
+
models:
|
|
290
|
+
- name: fast-local
|
|
291
|
+
provider: ollama
|
|
292
|
+
model: qwen3:0.6b
|
|
293
|
+
apiBase: http://127.0.0.1:11434/v1
|
|
294
|
+
roles: [chat, agent]
|
|
295
|
+
capabilities: [tool_use]
|
|
296
|
+
defaultCompletionOptions:
|
|
297
|
+
temperature: 0.2
|
|
298
|
+
maxTokens: 2048
|
|
299
|
+
requestOptions:
|
|
300
|
+
timeout: 60 # seconds
|
|
301
|
+
|
|
302
|
+
- name: remote-gpt
|
|
303
|
+
provider: openai
|
|
304
|
+
model: gpt-4o-mini
|
|
305
|
+
apiKey: $OPENAI_API_KEY # literal, $VAR, or ${VAR}
|
|
306
|
+
roles: [chat]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Selection order: the file's `default` entry, else the first entry with role
|
|
310
|
+
`chat`, else the first entry. `sangam models` merges those configured entries
|
|
311
|
+
with the model ids advertised by probed OpenAI-compatible runtimes (Ollama on
|
|
312
|
+
`127.0.0.1:11434`, LM Studio on `127.0.0.1:1234`, and every configured
|
|
313
|
+
`apiBase`) via `/v1/models`. Probing is read-only and best-effort — sangam never
|
|
314
|
+
installs a model runtime. Override the catalog path with `SANGAM_MODELS_FILE` or
|
|
315
|
+
`sangam models --catalog <path>`.
|
|
316
|
+
|
|
317
|
+
`requestOptions` carries transport-level settings for the entry's HTTP calls.
|
|
318
|
+
`timeout` (seconds) is honoured on every chat-completions request and overrides
|
|
319
|
+
the `SANGAM_LLM_TIMEOUT` environment variable (which defaults the timeout to
|
|
320
|
+
120 s). Invalid or non-positive values are ignored.
|
|
321
|
+
|
|
322
|
+
### As a library
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
from sangam import SangamCLI
|
|
326
|
+
|
|
327
|
+
cli = SangamCLI()
|
|
328
|
+
result = cli.execute_task("type check main.py")
|
|
329
|
+
print(result)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
The runtime contracts are importable for building backends:
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
from sangam.core import Executor, RunSpec, RunResult
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
The agent harness is importable too:
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from sangam.core.agent import Agent
|
|
342
|
+
from sangam.core.planner import Planner
|
|
343
|
+
from sangam.core.tools import ToolRegistry
|
|
344
|
+
from sangam.core.session_store import SessionStore
|
|
345
|
+
from sangam.core.model import (
|
|
346
|
+
ModelClient,
|
|
347
|
+
OpenAIModelClient,
|
|
348
|
+
LocalModelClient,
|
|
349
|
+
build_model_client,
|
|
350
|
+
)
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Project Structure
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
sangam/
|
|
357
|
+
├── __init__.py # Package exports
|
|
358
|
+
├── cli/
|
|
359
|
+
│ ├── main.py # CLI surface (argparse, REPL, batch mode)
|
|
360
|
+
│ └── commands/
|
|
361
|
+
│ ├── agent.py # sangam agent "<goal>"
|
|
362
|
+
│ ├── models.py # sangam models (list/select from models.yaml)
|
|
363
|
+
│ ├── exec.py # sangam exec --runtime <rt> <command>
|
|
364
|
+
│ └── serve.py # sangam serve (headless HTTP API server)
|
|
365
|
+
├── core/
|
|
366
|
+
│ ├── engine.py # Core engine (config + logger + task engine wiring)
|
|
367
|
+
│ ├── agent.py # Agent orchestrator (plan → act → observe → reflect)
|
|
368
|
+
│ ├── planner.py # Goal → step plan
|
|
369
|
+
│ ├── memory.py # Conversation history + working-set
|
|
370
|
+
│ ├── session_store.py # SQLite sessions/messages/usage + FTS5 search
|
|
371
|
+
│ ├── sandbox.py # SandboxPolicy, SandboxedExecutor, resource limits
|
|
372
|
+
│ ├── model/
|
|
373
|
+
│ │ ├── __init__.py # exports + build_model_client(config) factory
|
|
374
|
+
│ │ ├── client.py # ModelClient protocol + data contracts
|
|
375
|
+
│ │ ├── catalog.py # ~/.sangam/models.yaml catalog (load/select/probe)
|
|
376
|
+
│ │ ├── model.py # OpenAIModelClient (OpenAI-compatible)
|
|
377
|
+
│ │ └── local.py # LocalModelClient (local providers, e.g. Ollama/LM Studio)
|
|
378
|
+
│ ├── tools/
|
|
379
|
+
│ │ ├── registry.py # Tool, ToolResult, ToolRegistry, JSON-schema gen
|
|
380
|
+
│ │ ├── file_tools.py # read_file, write_file, edit_file, list_files, search
|
|
381
|
+
│ │ ├── exec_tools.py # run_python, run_js, run_container, run_shell, install_deps
|
|
382
|
+
│ │ └── type_check_tools.py # type_check, run_tests, suggest_fixes
|
|
383
|
+
│ └── runtime/
|
|
384
|
+
│ ├── base.py # Executor protocol, RunSpec, RunResult contracts
|
|
385
|
+
│ ├── venv.py # VenvExecutor (isolated venv + pip + run Python)
|
|
386
|
+
│ ├── nvm.py # NvmExecutor (nvm/npm, JS/React)
|
|
387
|
+
│ ├── shell.py # ShellExecutor (native bash/zsh, detect_shell)
|
|
388
|
+
│ ├── container.py # ContainerExecutor (Docker/Podman)
|
|
389
|
+
│ ├── subprocess.py # SubprocessExecutor (plain subprocess fallback)
|
|
390
|
+
│ ├── detect.py # Runtime auto-detection → executor
|
|
391
|
+
│ └── registry.py # EnvironmentRegistry (~/.sangam/environments.json)
|
|
392
|
+
├── server/ # Headless HTTP API server (Flask)
|
|
393
|
+
│ ├── __init__.py # Flask app exports
|
|
394
|
+
│ └── http_api.py # create_app factory, per-request SessionStore, SSE
|
|
395
|
+
├── task_engine.py # Natural-language task parsing and execution
|
|
396
|
+
├── sangam_integration.py # mypy subprocess wrapper and JSON parsing
|
|
397
|
+
├── file_ops.py # File read/write/analysis operations
|
|
398
|
+
├── logger.py # Logging and JSONL task history
|
|
399
|
+
├── config.py # Configuration management
|
|
400
|
+
└── mypy_cli.py # Backward-compatible shim (re-exports cli/main + core)
|
|
401
|
+
tests/ # pytest test suite
|
|
402
|
+
docs/ # Architecture docs
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Running Tests
|
|
406
|
+
|
|
407
|
+
The test suite uses [pytest](https://docs.pytest.org/). Install it if you don't have it:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
pip install pytest
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Then run the tests from the project root:
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
python -m pytest tests/ -v
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Or with the `pytest` command directly:
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
pytest tests/
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
To run a single test file:
|
|
426
|
+
|
|
427
|
+
```bash
|
|
428
|
+
pytest tests/test_file_ops.py
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
To run a single test:
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
pytest tests/test_file_ops.py::TestFileOperations::test_read_file
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
The mypy integration tests mock the `mypy` subprocess, so they run even if mypy is not installed.
|
|
438
|
+
|
|
439
|
+
## Simulation Tests
|
|
440
|
+
|
|
441
|
+
Beyond the unit tests, `sangam` ships a **live simulation suite** that drives
|
|
442
|
+
real runtimes end-to-end — no mocking of venv, subprocess, or the model
|
|
443
|
+
endpoint. These live in `tests/simulation/` and are tagged with the
|
|
444
|
+
`simulation` pytest marker, so they are excluded from the default run and only
|
|
445
|
+
execute when requested.
|
|
446
|
+
|
|
447
|
+
**What they cover**
|
|
448
|
+
|
|
449
|
+
- `test_sim_venv_executor.py` — `VenvExecutor`: real venv creation (idempotent
|
|
450
|
+
`prepare`), real pip installs of a local package, venv-vs-subprocess isolation
|
|
451
|
+
proof, `run_python` convenience + env passthrough, live timeout enforcement,
|
|
452
|
+
failure reporting, and sandbox-wrapped runs (allowed/disallowed cwd, proxy
|
|
453
|
+
clearing).
|
|
454
|
+
- `test_sim_shell_executor.py` — `ShellExecutor`: real-life `.sh` fixture
|
|
455
|
+
scripts (`simulate_release.sh` release pipeline, `analyze_logs.sh` log
|
|
456
|
+
analysis), one-off commands (pipelines, env, stdin, cwd), multi-line
|
|
457
|
+
`run_script` constructs, live timeouts, and sandbox policy.
|
|
458
|
+
- `test_sim_subprocess_executor.py` — `SubprocessExecutor`: real command
|
|
459
|
+
execution (PATH/absolute resolution, mypy `--version`), failure reporting,
|
|
460
|
+
stdin/env/cwd, live timeouts, sandbox enforcement (filesystem scope, default/
|
|
461
|
+
max timeout clamping, proxy clearing), and **live POSIX resource-limit
|
|
462
|
+
enforcement** (`fsize`, `cpu_time`, `nofile`).
|
|
463
|
+
- `test_sim_openai_endpoint.py` — a real OpenAI-compatible endpoint (the
|
|
464
|
+
device's local Ollama at `http://localhost:11434/v1`, standing in for any
|
|
465
|
+
provider the future `ModelClient` will target): `/v1/models`, chat
|
|
466
|
+
completions (single/multi-turn, system prompt, usage accounting), SSE
|
|
467
|
+
streaming, tool-calling, and error-path validation.
|
|
468
|
+
|
|
469
|
+
**Fixtures** — real-life usage-case files live in `tests/fixtures/real_life/`
|
|
470
|
+
(`simulate_release.sh`, `analyze_logs.sh`, `report_env.py`, sample logs, and a
|
|
471
|
+
small `src/` tree). The endpoint and model are overridable via
|
|
472
|
+
`SANGAM_OLLAMA_BASE_URL` and `SANGAM_OLLAMA_MODEL` (default `qwen3:0.6b`).
|
|
473
|
+
|
|
474
|
+
**Running the suite**
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
# All live simulation tests
|
|
478
|
+
pytest -m simulation
|
|
479
|
+
|
|
480
|
+
# A single backend
|
|
481
|
+
pytest -m simulation tests/simulation/test_sim_shell_executor.py
|
|
482
|
+
|
|
483
|
+
# Verbose runner with per-test traces, live logs, and a timestamped log file
|
|
484
|
+
./run_live_tests.sh
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
The endpoint tests **skip** (never fail) when Ollama is not reachable or no
|
|
488
|
+
model is pulled, so the default suite stays green without it. A full run is
|
|
489
|
+
~60 tests (221 passed / 1 skipped across the whole suite; `pytest -m "not
|
|
490
|
+
simulation"` = 162 for CI).
|
|
491
|
+
|
|
492
|
+
## License
|
|
493
|
+
|
|
494
|
+
MIT
|