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.
Files changed (89) hide show
  1. sangam-0.1.6/PKG-INFO +494 -0
  2. sangam-0.1.6/README.md +465 -0
  3. sangam-0.1.6/sangam/__init__.py +28 -0
  4. sangam-0.1.6/sangam/cli/__init__.py +5 -0
  5. sangam-0.1.6/sangam/cli/chat.py +1247 -0
  6. sangam-0.1.6/sangam/cli/commands/__init__.py +11 -0
  7. sangam-0.1.6/sangam/cli/commands/agent.py +137 -0
  8. sangam-0.1.6/sangam/cli/commands/exec.py +149 -0
  9. sangam-0.1.6/sangam/cli/commands/models.py +224 -0
  10. sangam-0.1.6/sangam/cli/commands/serve.py +86 -0
  11. sangam-0.1.6/sangam/cli/interactive.py +754 -0
  12. sangam-0.1.6/sangam/cli/main.py +382 -0
  13. sangam-0.1.6/sangam/cli/markdown.py +161 -0
  14. sangam-0.1.6/sangam/cli/spinner.py +98 -0
  15. sangam-0.1.6/sangam/config.py +99 -0
  16. sangam-0.1.6/sangam/core/__init__.py +47 -0
  17. sangam-0.1.6/sangam/core/agent.py +694 -0
  18. sangam-0.1.6/sangam/core/engine.py +77 -0
  19. sangam-0.1.6/sangam/core/memory.py +326 -0
  20. sangam-0.1.6/sangam/core/model/__init__.py +127 -0
  21. sangam-0.1.6/sangam/core/model/catalog.py +819 -0
  22. sangam-0.1.6/sangam/core/model/client.py +175 -0
  23. sangam-0.1.6/sangam/core/model/local.py +298 -0
  24. sangam-0.1.6/sangam/core/model/model.py +335 -0
  25. sangam-0.1.6/sangam/core/planner.py +406 -0
  26. sangam-0.1.6/sangam/core/runtime/__init__.py +54 -0
  27. sangam-0.1.6/sangam/core/runtime/base.py +156 -0
  28. sangam-0.1.6/sangam/core/runtime/container.py +266 -0
  29. sangam-0.1.6/sangam/core/runtime/detect.py +140 -0
  30. sangam-0.1.6/sangam/core/runtime/nvm.py +362 -0
  31. sangam-0.1.6/sangam/core/runtime/registry.py +195 -0
  32. sangam-0.1.6/sangam/core/runtime/shell.py +253 -0
  33. sangam-0.1.6/sangam/core/runtime/subprocess.py +157 -0
  34. sangam-0.1.6/sangam/core/runtime/venv.py +261 -0
  35. sangam-0.1.6/sangam/core/sandbox.py +326 -0
  36. sangam-0.1.6/sangam/core/session_store.py +726 -0
  37. sangam-0.1.6/sangam/core/tools/__init__.py +34 -0
  38. sangam-0.1.6/sangam/core/tools/agent_tools.py +191 -0
  39. sangam-0.1.6/sangam/core/tools/exec_tools.py +244 -0
  40. sangam-0.1.6/sangam/core/tools/file_tools.py +181 -0
  41. sangam-0.1.6/sangam/core/tools/qa_tools.py +120 -0
  42. sangam-0.1.6/sangam/core/tools/registry.py +398 -0
  43. sangam-0.1.6/sangam/core/tools/time_tools.py +81 -0
  44. sangam-0.1.6/sangam/core/tools/type_check_tools.py +296 -0
  45. sangam-0.1.6/sangam/file_ops.py +157 -0
  46. sangam-0.1.6/sangam/logger.py +139 -0
  47. sangam-0.1.6/sangam/mypy_cli.py +12 -0
  48. sangam-0.1.6/sangam/sangam_integration.py +264 -0
  49. sangam-0.1.6/sangam/server/__init__.py +31 -0
  50. sangam-0.1.6/sangam/server/http_api.py +597 -0
  51. sangam-0.1.6/sangam/task_engine.py +314 -0
  52. sangam-0.1.6/sangam.egg-info/PKG-INFO +494 -0
  53. sangam-0.1.6/sangam.egg-info/SOURCES.txt +87 -0
  54. sangam-0.1.6/sangam.egg-info/dependency_links.txt +1 -0
  55. sangam-0.1.6/sangam.egg-info/entry_points.txt +2 -0
  56. sangam-0.1.6/sangam.egg-info/requires.txt +2 -0
  57. sangam-0.1.6/sangam.egg-info/top_level.txt +1 -0
  58. sangam-0.1.6/setup.cfg +4 -0
  59. sangam-0.1.6/setup.py +41 -0
  60. sangam-0.1.6/tests/test_agent.py +439 -0
  61. sangam-0.1.6/tests/test_agent_tools.py +255 -0
  62. sangam-0.1.6/tests/test_cli_exec.py +138 -0
  63. sangam-0.1.6/tests/test_cli_interactive.py +1808 -0
  64. sangam-0.1.6/tests/test_cli_serve.py +100 -0
  65. sangam-0.1.6/tests/test_config.py +113 -0
  66. sangam-0.1.6/tests/test_file_ops.py +129 -0
  67. sangam-0.1.6/tests/test_install_sh.py +326 -0
  68. sangam-0.1.6/tests/test_interactive_prompts.py +529 -0
  69. sangam-0.1.6/tests/test_logger.py +62 -0
  70. sangam-0.1.6/tests/test_memory.py +238 -0
  71. sangam-0.1.6/tests/test_model_catalog.py +629 -0
  72. sangam-0.1.6/tests/test_model_client.py +508 -0
  73. sangam-0.1.6/tests/test_planner.py +244 -0
  74. sangam-0.1.6/tests/test_runtime_base.py +117 -0
  75. sangam-0.1.6/tests/test_runtime_container.py +170 -0
  76. sangam-0.1.6/tests/test_runtime_detect.py +101 -0
  77. sangam-0.1.6/tests/test_runtime_nvm.py +190 -0
  78. sangam-0.1.6/tests/test_runtime_registry.py +190 -0
  79. sangam-0.1.6/tests/test_runtime_shell.py +130 -0
  80. sangam-0.1.6/tests/test_runtime_subprocess.py +125 -0
  81. sangam-0.1.6/tests/test_runtime_venv.py +144 -0
  82. sangam-0.1.6/tests/test_sandbox.py +224 -0
  83. sangam-0.1.6/tests/test_sangam_integration.py +250 -0
  84. sangam-0.1.6/tests/test_server_http_api.py +243 -0
  85. sangam-0.1.6/tests/test_session_store.py +285 -0
  86. sangam-0.1.6/tests/test_spinner.py +140 -0
  87. sangam-0.1.6/tests/test_task_engine.py +109 -0
  88. sangam-0.1.6/tests/test_tools.py +1019 -0
  89. 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