sallm-agent 0.1.0__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 (49) hide show
  1. sallm_agent-0.1.0/.gitignore +17 -0
  2. sallm_agent-0.1.0/PKG-INFO +155 -0
  3. sallm_agent-0.1.0/README.md +138 -0
  4. sallm_agent-0.1.0/pyproject.toml +45 -0
  5. sallm_agent-0.1.0/src/sallm/__init__.py +38 -0
  6. sallm_agent-0.1.0/src/sallm/agent.py +412 -0
  7. sallm_agent-0.1.0/src/sallm/cli/__init__.py +6 -0
  8. sallm_agent-0.1.0/src/sallm/cli/__main__.py +4 -0
  9. sallm_agent-0.1.0/src/sallm/cli/chat.py +357 -0
  10. sallm_agent-0.1.0/src/sallm/cli/display.py +242 -0
  11. sallm_agent-0.1.0/src/sallm/cli/optimize_cmd.py +117 -0
  12. sallm_agent-0.1.0/src/sallm/context.py +128 -0
  13. sallm_agent-0.1.0/src/sallm/control.py +172 -0
  14. sallm_agent-0.1.0/src/sallm/extract_queue.py +165 -0
  15. sallm_agent-0.1.0/src/sallm/legacy_ask.py +164 -0
  16. sallm_agent-0.1.0/src/sallm/llm.py +44 -0
  17. sallm_agent-0.1.0/src/sallm/memory/__init__.py +52 -0
  18. sallm_agent-0.1.0/src/sallm/memory/chunking.py +56 -0
  19. sallm_agent-0.1.0/src/sallm/memory/config.py +85 -0
  20. sallm_agent-0.1.0/src/sallm/memory/embedding.py +44 -0
  21. sallm_agent-0.1.0/src/sallm/memory/gates.py +48 -0
  22. sallm_agent-0.1.0/src/sallm/memory/index.py +131 -0
  23. sallm_agent-0.1.0/src/sallm/memory/lance.py +204 -0
  24. sallm_agent-0.1.0/src/sallm/memory/query.py +104 -0
  25. sallm_agent-0.1.0/src/sallm/memory/retrieval.py +28 -0
  26. sallm_agent-0.1.0/src/sallm/memory/types.py +69 -0
  27. sallm_agent-0.1.0/src/sallm/messages.py +14 -0
  28. sallm_agent-0.1.0/src/sallm/metrics.py +46 -0
  29. sallm_agent-0.1.0/src/sallm/models.py +79 -0
  30. sallm_agent-0.1.0/src/sallm/optimization/__init__.py +21 -0
  31. sallm_agent-0.1.0/src/sallm/optimization/artifacts.py +58 -0
  32. sallm_agent-0.1.0/src/sallm/optimization/dataset.py +43 -0
  33. sallm_agent-0.1.0/src/sallm/optimization/metrics.py +42 -0
  34. sallm_agent-0.1.0/src/sallm/optimization/search.py +154 -0
  35. sallm_agent-0.1.0/src/sallm/profiles/gemma4-e4b-v1.json +22 -0
  36. sallm_agent-0.1.0/src/sallm/prom.py +430 -0
  37. sallm_agent-0.1.0/src/sallm/prompt.py +177 -0
  38. sallm_agent-0.1.0/src/sallm/receipt.py +176 -0
  39. sallm_agent-0.1.0/src/sallm/skills.py +70 -0
  40. sallm_agent-0.1.0/src/sallm/state/__init__.py +17 -0
  41. sallm_agent-0.1.0/src/sallm/state/models.py +98 -0
  42. sallm_agent-0.1.0/src/sallm/state/repository.py +370 -0
  43. sallm_agent-0.1.0/src/sallm/tools/__init__.py +109 -0
  44. sallm_agent-0.1.0/src/sallm/tools/calc.py +152 -0
  45. sallm_agent-0.1.0/src/sallm/tools/dig.py +86 -0
  46. sallm_agent-0.1.0/src/sallm/tools/echo.py +35 -0
  47. sallm_agent-0.1.0/src/sallm/tools/runner.py +229 -0
  48. sallm_agent-0.1.0/src/sallm/trace.py +550 -0
  49. sallm_agent-0.1.0/src/sallm/turn.py +230 -0
@@ -0,0 +1,17 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ .idea/
9
+ .ruff_cache/
10
+ .mypy_cache/
11
+ .pytest_cache/
12
+ *.egg
13
+ .DS_Store
14
+ uv.lock
15
+ /data
16
+ .sallm-lancedb/
17
+ .sallm*
@@ -0,0 +1,155 @@
1
+ Metadata-Version: 2.4
2
+ Name: sallm-agent
3
+ Version: 0.1.0
4
+ Summary: Minimal tool-calling agent over LiteLLM, tuned for local Ollama models
5
+ Project-URL: Homepage, https://github.com/codref/sallm-agent
6
+ Project-URL: Repository, https://github.com/codref/sallm-agent
7
+ Project-URL: Issues, https://github.com/codref/sallm-agent/issues
8
+ Requires-Python: >=3.12
9
+ Requires-Dist: lancedb
10
+ Requires-Dist: litellm
11
+ Requires-Dist: peewee
12
+ Requires-Dist: rich
13
+ Requires-Dist: typer
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest; extra == 'dev'
16
+ Description-Content-Type: text/markdown
17
+
18
+ # sallm-agent
19
+
20
+ Minimal tool-calling agent (`sallm`) for **local small LLMs** (default: Gemma 4 4B via Ollama).
21
+
22
+ **Focus:** keep context predictable over long sessions — durable SQLite state, LanceDB retrieval, a skill stack, and a visible `ContextReceipt` that explains token spend.
23
+
24
+ Not an invisible RAG black box: raw messages stay canonical; vectors are a rebuildable index; derived facts must cite source message ids.
25
+
26
+ ## Setup
27
+
28
+ ```bash
29
+ ollama pull gemma4:e4b-it-qat
30
+ ollama pull qwen3-embedding:0.6b
31
+
32
+ uv sync --extra dev
33
+ ```
34
+
35
+ Core deps include `peewee` (SQLite ORM) and `lancedb` (vector index). There is **no** DSPy/Pydantic dependency.
36
+
37
+ ## Turn pipeline
38
+
39
+ ```
40
+ user → persist raw message
41
+ → goal/skill control (small JSON call)
42
+ → vector retrieve (Qwen embed + LanceDB)
43
+ → budgeted prompt + ReAct ```run tools
44
+ → persist answer
45
+ → extract grounded facts + index chunks
46
+ ```
47
+
48
+ ## Library
49
+
50
+ ```python
51
+ from sallm import Agent, RetrievalConfig, Skill, SkillRegistry
52
+ from sallm.tools import builtin_tools
53
+
54
+ agent = Agent(
55
+ tools=builtin_tools(("calc", "echo")),
56
+ state_path="/tmp/sallm/state.db",
57
+ vector_path="/tmp/sallm/vectors",
58
+ session_id="demo",
59
+ retrieval=RetrievalConfig(
60
+ memory_gate=True,
61
+ search_mode="dense", # or "hybrid"
62
+ use_instruct=True,
63
+ use_rewrite=False,
64
+ use_hyde=False,
65
+ ),
66
+ )
67
+ result = agent.ask("Remember the code is PURPLE-42.")
68
+ print(result["answer"])
69
+ print(result["receipt"]) # ContextReceipt as dict
70
+ print(result["goal"], result["stack"])
71
+ ```
72
+
73
+ Resume by reusing `state_path` + `session_id`.
74
+
75
+ ### VectorStore contract
76
+
77
+ Implement `upsert` / `search` / `delete_session` / `close` (see `sallm.memory.types.VectorStore`). Default: `LanceVectorStore`. A future **pgvector** adapter can satisfy the same dataclasses (`VectorRecord`, `VectorQuery`, `VectorHit`) without changing the agent.
78
+
79
+ SQLite stores chunk text + `indexed` flags; LanceDB is rebuilt from those rows after a crash.
80
+
81
+ ### Skills
82
+
83
+ Default skill is `converse`. Register more with `SkillRegistry` (name, description, prompt fragment, optional tool subset).
84
+
85
+ ### Compiled profiles
86
+
87
+ Neutral JSON under `sallm/profiles/` (instructions + demos + budgets). Offline:
88
+
89
+ ```bash
90
+ uv run sallm optimize --dataset data/cases.jsonl --task controller --out /tmp/profile.json
91
+ ```
92
+
93
+ `sallm chat` never optimizes at startup; it only loads a profile.
94
+
95
+ ## CLI
96
+
97
+ ```bash
98
+ # Durable long session (recommended)
99
+ uv run sallm chat \
100
+ --state-path .sallm/state.db \
101
+ --vector-path .sallm/vectors \
102
+ --session long1 \
103
+ --retrieval-query instruct \
104
+ --search dense \
105
+ --memory-gate \
106
+ --extract waterfall \
107
+ --tools echo,calc
108
+
109
+ uv run sallm chat --show-prompt
110
+ uv run sallm chat --script tests/fixtures/sample_conversation.txt
111
+ ```
112
+
113
+ Slash commands: `/help`, `/clear`, `/history`, `/prompt`, `/state`, `/stack`, `/memory`, `/context`, `/quit`.
114
+
115
+ ### Tool contract
116
+
117
+ | Rule | Detail |
118
+ |------|--------|
119
+ | Identity | Tool name = first argv token |
120
+ | Help | Every tool supports `--help` |
121
+ | Args | CLI flags only (no JSON blobs) |
122
+ | Intermediate | stdout may start with `[intermediate]` |
123
+
124
+ ````markdown
125
+ ```run
126
+ calc --expression "2**10"
127
+ ```
128
+ ````
129
+
130
+ Shipped tools: `echo`, `calc`, `dig`.
131
+
132
+ ### Legacy context optimizers
133
+
134
+ Still available without durable state: `--context max-messages|summarize`. Prefer `--state-path` + retrieval for hour-scale sessions.
135
+
136
+ ## Tests
137
+
138
+ ```bash
139
+ uv run pytest tests/ -v
140
+ # E2E needs Ollama + gemma4:e4b-it-qat (+ qwen3-embedding:0.6b for stack memory)
141
+ ```
142
+
143
+ ## Limits
144
+
145
+ Retrieval improves grounding; it does **not** guarantee the model never invents facts. Source-tagged memory and `ContextReceipt` make misses inspectable.
146
+
147
+ ## How it works
148
+
149
+ Walkthrough with an example, stage-by-stage flow, token-budget simulation, and hypothesis checks: [docs/how-the-agent-works.md](docs/how-the-agent-works.md).
150
+
151
+ When a script turn (briefing / transcript) is larger than the history budget: [docs/oversized-briefings.md](docs/oversized-briefings.md).
152
+
153
+ Offline prompt/parameter tuning: [docs/optimize-prompts.md](docs/optimize-prompts.md).
154
+
155
+ Skills (selection, stack, tools): [docs/skills.md](docs/skills.md).
@@ -0,0 +1,138 @@
1
+ # sallm-agent
2
+
3
+ Minimal tool-calling agent (`sallm`) for **local small LLMs** (default: Gemma 4 4B via Ollama).
4
+
5
+ **Focus:** keep context predictable over long sessions — durable SQLite state, LanceDB retrieval, a skill stack, and a visible `ContextReceipt` that explains token spend.
6
+
7
+ Not an invisible RAG black box: raw messages stay canonical; vectors are a rebuildable index; derived facts must cite source message ids.
8
+
9
+ ## Setup
10
+
11
+ ```bash
12
+ ollama pull gemma4:e4b-it-qat
13
+ ollama pull qwen3-embedding:0.6b
14
+
15
+ uv sync --extra dev
16
+ ```
17
+
18
+ Core deps include `peewee` (SQLite ORM) and `lancedb` (vector index). There is **no** DSPy/Pydantic dependency.
19
+
20
+ ## Turn pipeline
21
+
22
+ ```
23
+ user → persist raw message
24
+ → goal/skill control (small JSON call)
25
+ → vector retrieve (Qwen embed + LanceDB)
26
+ → budgeted prompt + ReAct ```run tools
27
+ → persist answer
28
+ → extract grounded facts + index chunks
29
+ ```
30
+
31
+ ## Library
32
+
33
+ ```python
34
+ from sallm import Agent, RetrievalConfig, Skill, SkillRegistry
35
+ from sallm.tools import builtin_tools
36
+
37
+ agent = Agent(
38
+ tools=builtin_tools(("calc", "echo")),
39
+ state_path="/tmp/sallm/state.db",
40
+ vector_path="/tmp/sallm/vectors",
41
+ session_id="demo",
42
+ retrieval=RetrievalConfig(
43
+ memory_gate=True,
44
+ search_mode="dense", # or "hybrid"
45
+ use_instruct=True,
46
+ use_rewrite=False,
47
+ use_hyde=False,
48
+ ),
49
+ )
50
+ result = agent.ask("Remember the code is PURPLE-42.")
51
+ print(result["answer"])
52
+ print(result["receipt"]) # ContextReceipt as dict
53
+ print(result["goal"], result["stack"])
54
+ ```
55
+
56
+ Resume by reusing `state_path` + `session_id`.
57
+
58
+ ### VectorStore contract
59
+
60
+ Implement `upsert` / `search` / `delete_session` / `close` (see `sallm.memory.types.VectorStore`). Default: `LanceVectorStore`. A future **pgvector** adapter can satisfy the same dataclasses (`VectorRecord`, `VectorQuery`, `VectorHit`) without changing the agent.
61
+
62
+ SQLite stores chunk text + `indexed` flags; LanceDB is rebuilt from those rows after a crash.
63
+
64
+ ### Skills
65
+
66
+ Default skill is `converse`. Register more with `SkillRegistry` (name, description, prompt fragment, optional tool subset).
67
+
68
+ ### Compiled profiles
69
+
70
+ Neutral JSON under `sallm/profiles/` (instructions + demos + budgets). Offline:
71
+
72
+ ```bash
73
+ uv run sallm optimize --dataset data/cases.jsonl --task controller --out /tmp/profile.json
74
+ ```
75
+
76
+ `sallm chat` never optimizes at startup; it only loads a profile.
77
+
78
+ ## CLI
79
+
80
+ ```bash
81
+ # Durable long session (recommended)
82
+ uv run sallm chat \
83
+ --state-path .sallm/state.db \
84
+ --vector-path .sallm/vectors \
85
+ --session long1 \
86
+ --retrieval-query instruct \
87
+ --search dense \
88
+ --memory-gate \
89
+ --extract waterfall \
90
+ --tools echo,calc
91
+
92
+ uv run sallm chat --show-prompt
93
+ uv run sallm chat --script tests/fixtures/sample_conversation.txt
94
+ ```
95
+
96
+ Slash commands: `/help`, `/clear`, `/history`, `/prompt`, `/state`, `/stack`, `/memory`, `/context`, `/quit`.
97
+
98
+ ### Tool contract
99
+
100
+ | Rule | Detail |
101
+ |------|--------|
102
+ | Identity | Tool name = first argv token |
103
+ | Help | Every tool supports `--help` |
104
+ | Args | CLI flags only (no JSON blobs) |
105
+ | Intermediate | stdout may start with `[intermediate]` |
106
+
107
+ ````markdown
108
+ ```run
109
+ calc --expression "2**10"
110
+ ```
111
+ ````
112
+
113
+ Shipped tools: `echo`, `calc`, `dig`.
114
+
115
+ ### Legacy context optimizers
116
+
117
+ Still available without durable state: `--context max-messages|summarize`. Prefer `--state-path` + retrieval for hour-scale sessions.
118
+
119
+ ## Tests
120
+
121
+ ```bash
122
+ uv run pytest tests/ -v
123
+ # E2E needs Ollama + gemma4:e4b-it-qat (+ qwen3-embedding:0.6b for stack memory)
124
+ ```
125
+
126
+ ## Limits
127
+
128
+ Retrieval improves grounding; it does **not** guarantee the model never invents facts. Source-tagged memory and `ContextReceipt` make misses inspectable.
129
+
130
+ ## How it works
131
+
132
+ Walkthrough with an example, stage-by-stage flow, token-budget simulation, and hypothesis checks: [docs/how-the-agent-works.md](docs/how-the-agent-works.md).
133
+
134
+ When a script turn (briefing / transcript) is larger than the history budget: [docs/oversized-briefings.md](docs/oversized-briefings.md).
135
+
136
+ Offline prompt/parameter tuning: [docs/optimize-prompts.md](docs/optimize-prompts.md).
137
+
138
+ Skills (selection, stack, tools): [docs/skills.md](docs/skills.md).
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "sallm-agent"
3
+ version = "0.1.0"
4
+ description = "Minimal tool-calling agent over LiteLLM, tuned for local Ollama models"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "litellm",
9
+ "typer",
10
+ "rich",
11
+ "peewee",
12
+ "lancedb",
13
+ ]
14
+
15
+ [project.urls]
16
+ Homepage = "https://github.com/codref/sallm-agent"
17
+ Repository = "https://github.com/codref/sallm-agent"
18
+ Issues = "https://github.com/codref/sallm-agent/issues"
19
+
20
+ [project.scripts]
21
+ sallm = "sallm.cli.chat:app"
22
+ sallm-echo = "sallm.tools.echo:main"
23
+ sallm-calc = "sallm.tools.calc:main"
24
+ sallm-dig = "sallm.tools.dig:main"
25
+
26
+ [project.optional-dependencies]
27
+ dev = ["pytest"]
28
+
29
+ [build-system]
30
+ requires = ["hatchling"]
31
+ build-backend = "hatchling.build"
32
+
33
+ [tool.hatch.build.targets.sdist]
34
+ include = [
35
+ "src/sallm",
36
+ "README.md",
37
+ "pyproject.toml",
38
+ ]
39
+
40
+ [tool.hatch.build.targets.wheel]
41
+ packages = ["src/sallm"]
42
+
43
+ # Map src/sallm -> sallm in the wheel
44
+ [tool.hatch.build.targets.wheel.sources]
45
+ "src/sallm" = "sallm"
@@ -0,0 +1,38 @@
1
+ """Public package exports — agent + prompt + memory/state types."""
2
+
3
+ from .agent import Agent
4
+ from .memory import (
5
+ LanceVectorStore,
6
+ RetrievalConfig,
7
+ VectorHit,
8
+ VectorQuery,
9
+ VectorRecord,
10
+ VectorStore,
11
+ )
12
+ from .messages import DEFAULT_API_BASE, DEFAULT_MODEL
13
+ from .models import EmbeddingProfile, ModelProfile
14
+ from .prompt import CompiledProfile, Prompt
15
+ from .receipt import ContextReceipt
16
+ from .skills import Skill, SkillRegistry
17
+ from .tools import CliTool, ToolResult
18
+
19
+ __all__ = [
20
+ "Agent",
21
+ "CliTool",
22
+ "CompiledProfile",
23
+ "ContextReceipt",
24
+ "EmbeddingProfile",
25
+ "LanceVectorStore",
26
+ "ModelProfile",
27
+ "Prompt",
28
+ "RetrievalConfig",
29
+ "Skill",
30
+ "SkillRegistry",
31
+ "ToolResult",
32
+ "VectorHit",
33
+ "VectorQuery",
34
+ "VectorRecord",
35
+ "VectorStore",
36
+ "DEFAULT_MODEL",
37
+ "DEFAULT_API_BASE",
38
+ ]