litecoo 1.0.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.
- litecoo-1.0.0/.claude/skills/docx/SKILL.md +23 -0
- litecoo-1.0.0/.claude/skills/pdf/SKILL.md +24 -0
- litecoo-1.0.0/.claude/skills/pptx/SKILL.md +24 -0
- litecoo-1.0.0/.claude/skills/xlsx/SKILL.md +23 -0
- litecoo-1.0.0/.env.example +17 -0
- litecoo-1.0.0/.gitignore +70 -0
- litecoo-1.0.0/MEMORY.md +20 -0
- litecoo-1.0.0/PKG-INFO +138 -0
- litecoo-1.0.0/README.md +103 -0
- litecoo-1.0.0/config.yaml +32 -0
- litecoo-1.0.0/models.json +0 -0
- litecoo-1.0.0/pyproject.toml +53 -0
- litecoo-1.0.0/requirements.txt +11 -0
- litecoo-1.0.0/schedules.json +1 -0
- litecoo-1.0.0/src/litecoo/__init__.py +0 -0
- litecoo-1.0.0/src/litecoo/agent_loop.py +107 -0
- litecoo-1.0.0/src/litecoo/cli.py +18 -0
- litecoo-1.0.0/src/litecoo/context.py +57 -0
- litecoo-1.0.0/src/litecoo/custom_router.py +260 -0
- litecoo-1.0.0/src/litecoo/main.py +978 -0
- litecoo-1.0.0/src/litecoo/mcp_client.py +272 -0
- litecoo-1.0.0/src/litecoo/memory.py +93 -0
- litecoo-1.0.0/src/litecoo/scheduler.py +135 -0
- litecoo-1.0.0/src/litecoo/skills.py +91 -0
- litecoo-1.0.0/src/litecoo/store.py +232 -0
- litecoo-1.0.0/src/litecoo/tools/__init__.py +67 -0
- litecoo-1.0.0/src/litecoo/tools/bash.py +85 -0
- litecoo-1.0.0/src/litecoo/tools/docx.py +80 -0
- litecoo-1.0.0/src/litecoo/tools/file_ops.py +99 -0
- litecoo-1.0.0/src/litecoo/tools/memory.py +51 -0
- litecoo-1.0.0/src/litecoo/tools/pdf.py +85 -0
- litecoo-1.0.0/src/litecoo/tools/pptx.py +81 -0
- litecoo-1.0.0/src/litecoo/tools/web_fetch.py +66 -0
- litecoo-1.0.0/src/litecoo/tools/web_search.py +79 -0
- litecoo-1.0.0/src/litecoo/tools/xlsx.py +90 -0
- litecoo-1.0.0/tests/check_anthropic_sse.py +67 -0
- litecoo-1.0.0/tests/check_sse.py +57 -0
- litecoo-1.0.0/tests/run_integration_tests.py +289 -0
- litecoo-1.0.0/tests/test_api.py +20 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docx
|
|
3
|
+
description: Create and edit Microsoft Word (.docx) documents with formatted text, headings, tables, and styles.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DOCX Skill
|
|
7
|
+
|
|
8
|
+
You can create Word documents using the `create_docx` tool.
|
|
9
|
+
|
|
10
|
+
## Capabilities
|
|
11
|
+
- Create documents with multiple sections and headings (levels 0-4)
|
|
12
|
+
- Add formatted body paragraphs
|
|
13
|
+
- Set document metadata (author, title)
|
|
14
|
+
- Output to any writable path
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
When the user asks you to create a Word document (.docx file), use the `create_docx` tool with:
|
|
18
|
+
- `path`: where to save the file
|
|
19
|
+
- `title`: optional document title
|
|
20
|
+
- `sections`: array of `{heading, content, level}` objects
|
|
21
|
+
- `author`: optional author name
|
|
22
|
+
|
|
23
|
+
Always save documents to the user's Desktop or a path they specify. Confirm the file was created successfully.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pdf
|
|
3
|
+
description: Create PDF documents with formatted text, headings, and tables using ReportLab.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PDF Skill
|
|
7
|
+
|
|
8
|
+
You can create PDF documents using the `create_pdf` tool.
|
|
9
|
+
|
|
10
|
+
## Capabilities
|
|
11
|
+
- Create PDFs with title and multiple sections
|
|
12
|
+
- Support for A4 and Letter page sizes
|
|
13
|
+
- Formatted headings and body paragraphs
|
|
14
|
+
- Professional layout with margins
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
When the user asks you to create a PDF document (.pdf file), use the `create_pdf` tool with:
|
|
18
|
+
- `path`: where to save the file
|
|
19
|
+
- `title`: optional document title
|
|
20
|
+
- `sections`: array of `{heading, content}` objects
|
|
21
|
+
- `content`: body text (paragraphs separated by double newlines)
|
|
22
|
+
- `page_size`: "A4" or "Letter" (default A4)
|
|
23
|
+
|
|
24
|
+
Always save to the user's Desktop or specified path. Confirm the file was created.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pptx
|
|
3
|
+
description: Create PowerPoint (.pptx) presentations with slides, titles, bullet points, and speaker notes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# PPTX Skill
|
|
7
|
+
|
|
8
|
+
You can create PowerPoint presentations using the `create_pptx` tool.
|
|
9
|
+
|
|
10
|
+
## Capabilities
|
|
11
|
+
- Create multi-slide presentations
|
|
12
|
+
- Add slide titles and body content (bullet points)
|
|
13
|
+
- Include speaker notes per slide
|
|
14
|
+
- Set presentation title
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
When the user asks you to create a PowerPoint presentation (.pptx file), use the `create_pptx` tool with:
|
|
18
|
+
- `path`: where to save the file
|
|
19
|
+
- `title`: presentation title
|
|
20
|
+
- `slides`: array of `{title, content, notes}` objects
|
|
21
|
+
- `content`: bullet points separated by newlines
|
|
22
|
+
- `notes`: optional speaker notes
|
|
23
|
+
|
|
24
|
+
Always save to the user's Desktop or specified path. Confirm the file was created.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: xlsx
|
|
3
|
+
description: Create Excel (.xlsx) spreadsheets with multiple sheets, headers, styled columns, and data rows.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# XLSX Skill
|
|
7
|
+
|
|
8
|
+
You can create Excel spreadsheets using the `create_xlsx` tool.
|
|
9
|
+
|
|
10
|
+
## Capabilities
|
|
11
|
+
- Create workbooks with multiple sheets
|
|
12
|
+
- Add styled header rows with blue background
|
|
13
|
+
- Fill data rows
|
|
14
|
+
- Auto-sizing columns
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
When the user asks you to create an Excel spreadsheet (.xlsx file), use the `create_xlsx` tool with:
|
|
18
|
+
- `path`: where to save the file
|
|
19
|
+
- `sheets`: array of `{name, headers, rows}` objects
|
|
20
|
+
- `headers`: array of column names (optional)
|
|
21
|
+
- `rows`: array of arrays (each row is cell values)
|
|
22
|
+
|
|
23
|
+
Always save to the user's Desktop or specified path. Confirm the file was created.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# OpenRouter API Key (https://openrouter.ai/keys)
|
|
2
|
+
OPENROUTER_API_KEY=your_openrouter_key_here
|
|
3
|
+
|
|
4
|
+
# NVIDIA NIM API Key (https://build.nvidia.com/)
|
|
5
|
+
NVIDIA_API_KEY=your_nvidia_key_here
|
|
6
|
+
|
|
7
|
+
# OpenCodeZen API Key
|
|
8
|
+
OPENCODEZEN_API_KEY=your_opencodezen_key_here
|
|
9
|
+
|
|
10
|
+
# Config path (defaults to config.yaml in current directory)
|
|
11
|
+
COWORKFORVAS_CONFIG_PATH=config.yaml
|
|
12
|
+
|
|
13
|
+
# Optional tuning
|
|
14
|
+
# COWORKFORVAS_COOLDOWN_SECONDS=120
|
|
15
|
+
# COWORKFORVAS_MAX_CONTEXT_TOKENS=50000
|
|
16
|
+
# COWORKFORVAS_SESSION_TTL_DAYS=7
|
|
17
|
+
# COWORKFORVAS_DB_PATH=coworkforvas.db
|
litecoo-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Environments
|
|
2
|
+
.env
|
|
3
|
+
.venv
|
|
4
|
+
env/
|
|
5
|
+
venv/
|
|
6
|
+
ENV/
|
|
7
|
+
env.bak/
|
|
8
|
+
venv.bak/
|
|
9
|
+
|
|
10
|
+
# Byte-compiled / optimized / DLL files
|
|
11
|
+
__pycache__/
|
|
12
|
+
*.py[cod]
|
|
13
|
+
*$py.class
|
|
14
|
+
|
|
15
|
+
# Distribution / packaging
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
downloads/
|
|
20
|
+
eggs/
|
|
21
|
+
.eggs/
|
|
22
|
+
lib/
|
|
23
|
+
lib64/
|
|
24
|
+
parts/
|
|
25
|
+
sdist/
|
|
26
|
+
var/
|
|
27
|
+
wheels/
|
|
28
|
+
share/python-wheels/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
.installed.cfg
|
|
31
|
+
*.egg
|
|
32
|
+
MANIFEST
|
|
33
|
+
|
|
34
|
+
# PyInstaller
|
|
35
|
+
# Usually these files are written by a python script from a template
|
|
36
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
37
|
+
*.manifest
|
|
38
|
+
*.spec
|
|
39
|
+
|
|
40
|
+
# Installer logs
|
|
41
|
+
pip-log.txt
|
|
42
|
+
pip-delete-this-directory.txt
|
|
43
|
+
|
|
44
|
+
# Unit test / coverage reports
|
|
45
|
+
htmlcov/
|
|
46
|
+
.tox/
|
|
47
|
+
.nox/
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
.cache
|
|
51
|
+
nosetests.xml
|
|
52
|
+
coverage.xml
|
|
53
|
+
*.cover
|
|
54
|
+
*.py,cover
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
|
|
59
|
+
# Jupyter Notebook
|
|
60
|
+
.ipynb_checkpoints
|
|
61
|
+
|
|
62
|
+
# IDEs
|
|
63
|
+
.vscode/
|
|
64
|
+
.idea/
|
|
65
|
+
*.swp
|
|
66
|
+
*.swo
|
|
67
|
+
|
|
68
|
+
# Project specific
|
|
69
|
+
cowork_proxy.db
|
|
70
|
+
sessions/
|
litecoo-1.0.0/MEMORY.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# AI Context Memory
|
|
2
|
+
|
|
3
|
+
This document serves as a persistent context memory for the project.
|
|
4
|
+
|
|
5
|
+
## Project Architecture
|
|
6
|
+
- **Package name**: `coworkforvas` (litecoo v3).
|
|
7
|
+
- **Directory layout**: Standard `src/coworkforvas` and `tests/` structure.
|
|
8
|
+
- **Entry point**: `src/coworkforvas/cli.py:main` configures and runs `uvicorn`.
|
|
9
|
+
- **Frameworks**: `FastAPI` + `httpx` (proxy), SQLite (session persistence).
|
|
10
|
+
|
|
11
|
+
## Key Files
|
|
12
|
+
- `src/coworkforvas/main.py`: Defines the FastAPI app and Anthropic/OpenAI conversion logic.
|
|
13
|
+
- `src/coworkforvas/custom_router.py`: Handles upstream `httpx` logic.
|
|
14
|
+
- `src/coworkforvas/agent_loop.py`: Executes multi-step tools internally when `X-Agent-Loop: server` is provided.
|
|
15
|
+
- `src/coworkforvas/tools/`: Built-in tools directory (`web_fetch`, `web_search`, `bash`, file and office document generation). All dependencies added in `pyproject.toml`.
|
|
16
|
+
|
|
17
|
+
## Important Rules
|
|
18
|
+
- Local imports within `src/coworkforvas` must be relative (e.g. `from .store import get_session`).
|
|
19
|
+
- To run tests locally, install the package in editable mode with dev dependencies first (`pip install -e .[dev]`).
|
|
20
|
+
- Do not add arbitrary root scripts; use `pytest` for testing and `cli.py` for commands.
|
litecoo-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: litecoo
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Free LLM proxy for Cowork and OpenAI-compatible clients — no litellm, pure httpx routing
|
|
5
|
+
Project-URL: Homepage, https://github.com/Saisharathchandranandnetha/KrishiMitra_Beast
|
|
6
|
+
Project-URL: Repository, https://github.com/Saisharathchandranandnetha/KrishiMitra_Beast
|
|
7
|
+
License: MIT
|
|
8
|
+
Keywords: anthropic,cowork,free,litecoo,llm,openai,proxy
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
19
|
+
Requires-Dist: chromadb>=0.5.0
|
|
20
|
+
Requires-Dist: fastapi<0.129.0,>=0.128.0
|
|
21
|
+
Requires-Dist: httpx>=0.27.0
|
|
22
|
+
Requires-Dist: openpyxl>=3.1.2
|
|
23
|
+
Requires-Dist: pydantic>=2.12.3
|
|
24
|
+
Requires-Dist: python-docx>=1.1.0
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
26
|
+
Requires-Dist: python-pptx>=0.6.23
|
|
27
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
28
|
+
Requires-Dist: reportlab>=4.1.0
|
|
29
|
+
Requires-Dist: uvicorn<0.41.0,>=0.40.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: httpx; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# litecoo (litecoo v3)
|
|
37
|
+
|
|
38
|
+
**litecoo** (formerly litecoo) is a local FastAPI proxy that makes free LLM models (DeepSeek V4, Gemma, Nemotron) behave like Claude for Cowork Desktop and Claude Code. It handles the Anthropic protocol, agentic tool loops, session memory, and built-in tools — all without spending a cent on API calls.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🚀 System Architecture
|
|
43
|
+
|
|
44
|
+
```mermaid
|
|
45
|
+
graph TD
|
|
46
|
+
Client[Client (Cowork / curl)] --> API[FastAPI Proxy]
|
|
47
|
+
API --> Router[Model Router]
|
|
48
|
+
|
|
49
|
+
subgraph Core Features
|
|
50
|
+
Router --> Memory[SQLite Session Memory]
|
|
51
|
+
Router --> AgentLoop[Server-Side Agent Loop]
|
|
52
|
+
Router --> RateLimit[Cooldown / Rate Limiting]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
subgraph Built-in Tools
|
|
56
|
+
AgentLoop --> Fetch[Web Fetch]
|
|
57
|
+
AgentLoop --> Search[Web Search]
|
|
58
|
+
AgentLoop --> Bash[Bash Command]
|
|
59
|
+
AgentLoop --> FileOps[File Read/Write]
|
|
60
|
+
AgentLoop --> Office[Create PDF/DOCX/PPTX]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Router --> Provider[OpenRouter / DeepSeek / External APIs]
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 🛠️ Endpoints
|
|
67
|
+
|
|
68
|
+
| Endpoint | Format | Description |
|
|
69
|
+
|---|---|---|
|
|
70
|
+
| `POST /v1/messages` | Anthropic | For Claude Desktop and Cowork. Handles tool loops and SSE streaming. |
|
|
71
|
+
| `POST /v1/chat/completions` | OpenAI | For standard OpenAI clients, Claude Code, curl. |
|
|
72
|
+
| `GET /v1/models` | Standard | Returns the list of available aliases. |
|
|
73
|
+
| `GET /v1/sessions/{id}` | Internal | Inspect a session's history. |
|
|
74
|
+
| `DELETE /v1/sessions/{id}` | Internal | Clear a session from SQLite. |
|
|
75
|
+
| `GET /v1/cooldowns` | Internal | Check rate limit status for each model. |
|
|
76
|
+
| `GET /v1/usage` | Internal | Review token usage stats. |
|
|
77
|
+
|
|
78
|
+
## 📦 Built-in Tools
|
|
79
|
+
|
|
80
|
+
If the client doesn't send its own tool definitions, litecoo automatically injects these tools:
|
|
81
|
+
- `web_fetch`, `web_search`: DuckDuckGo and basic page scraping.
|
|
82
|
+
- `bash`: Local command execution.
|
|
83
|
+
- `read_file`, `write_file`: Read and write to disk.
|
|
84
|
+
- `create_pdf`, `create_docx`, `create_pptx`, `create_xlsx`: Generate rich documents.
|
|
85
|
+
|
|
86
|
+
Add the header `X-Agent-Loop: server` to let litecoo automatically execute multi-step tools server-side before returning the final text to the client.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 💻 Installation
|
|
91
|
+
|
|
92
|
+
To run it locally or use it as a library, install directly from source:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
python -m venv venv
|
|
96
|
+
# On Windows: venv\Scripts\activate
|
|
97
|
+
# On Mac/Linux: source venv/bin/activate
|
|
98
|
+
|
|
99
|
+
pip install litecoo
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Then run the proxy:
|
|
103
|
+
```bash
|
|
104
|
+
litecoo --host 0.0.0.0 --port 8000 --env-file .env
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 🔌 Connecting Clients
|
|
108
|
+
|
|
109
|
+
**Claude Desktop:**
|
|
110
|
+
Settings → Developer → API base URL → `http://localhost:8000`
|
|
111
|
+
|
|
112
|
+
**Claude Code:**
|
|
113
|
+
```bash
|
|
114
|
+
export ANTHROPIC_BASE_URL=http://localhost:8000
|
|
115
|
+
export ANTHROPIC_API_KEY=any-string
|
|
116
|
+
claude
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## ⬆️ How to Publish to PyPI
|
|
120
|
+
|
|
121
|
+
If you are a developer and want to push the latest changes to PyPI, follow these steps:
|
|
122
|
+
|
|
123
|
+
1. **Install build tools:**
|
|
124
|
+
```bash
|
|
125
|
+
pip install build twine
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
2. **Build the wheel and source distribution:**
|
|
129
|
+
```bash
|
|
130
|
+
python -m build
|
|
131
|
+
```
|
|
132
|
+
*This creates a `dist/` directory with a `.tar.gz` and `.whl` file.*
|
|
133
|
+
|
|
134
|
+
3. **Upload to PyPI:**
|
|
135
|
+
```bash
|
|
136
|
+
python -m twine upload dist/*
|
|
137
|
+
```
|
|
138
|
+
*You will be prompted for your PyPI API token (username `__token__`).*
|
litecoo-1.0.0/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# litecoo (litecoo v3)
|
|
2
|
+
|
|
3
|
+
**litecoo** (formerly litecoo) is a local FastAPI proxy that makes free LLM models (DeepSeek V4, Gemma, Nemotron) behave like Claude for Cowork Desktop and Claude Code. It handles the Anthropic protocol, agentic tool loops, session memory, and built-in tools — all without spending a cent on API calls.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 System Architecture
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
Client[Client (Cowork / curl)] --> API[FastAPI Proxy]
|
|
12
|
+
API --> Router[Model Router]
|
|
13
|
+
|
|
14
|
+
subgraph Core Features
|
|
15
|
+
Router --> Memory[SQLite Session Memory]
|
|
16
|
+
Router --> AgentLoop[Server-Side Agent Loop]
|
|
17
|
+
Router --> RateLimit[Cooldown / Rate Limiting]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
subgraph Built-in Tools
|
|
21
|
+
AgentLoop --> Fetch[Web Fetch]
|
|
22
|
+
AgentLoop --> Search[Web Search]
|
|
23
|
+
AgentLoop --> Bash[Bash Command]
|
|
24
|
+
AgentLoop --> FileOps[File Read/Write]
|
|
25
|
+
AgentLoop --> Office[Create PDF/DOCX/PPTX]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
Router --> Provider[OpenRouter / DeepSeek / External APIs]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 🛠️ Endpoints
|
|
32
|
+
|
|
33
|
+
| Endpoint | Format | Description |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `POST /v1/messages` | Anthropic | For Claude Desktop and Cowork. Handles tool loops and SSE streaming. |
|
|
36
|
+
| `POST /v1/chat/completions` | OpenAI | For standard OpenAI clients, Claude Code, curl. |
|
|
37
|
+
| `GET /v1/models` | Standard | Returns the list of available aliases. |
|
|
38
|
+
| `GET /v1/sessions/{id}` | Internal | Inspect a session's history. |
|
|
39
|
+
| `DELETE /v1/sessions/{id}` | Internal | Clear a session from SQLite. |
|
|
40
|
+
| `GET /v1/cooldowns` | Internal | Check rate limit status for each model. |
|
|
41
|
+
| `GET /v1/usage` | Internal | Review token usage stats. |
|
|
42
|
+
|
|
43
|
+
## 📦 Built-in Tools
|
|
44
|
+
|
|
45
|
+
If the client doesn't send its own tool definitions, litecoo automatically injects these tools:
|
|
46
|
+
- `web_fetch`, `web_search`: DuckDuckGo and basic page scraping.
|
|
47
|
+
- `bash`: Local command execution.
|
|
48
|
+
- `read_file`, `write_file`: Read and write to disk.
|
|
49
|
+
- `create_pdf`, `create_docx`, `create_pptx`, `create_xlsx`: Generate rich documents.
|
|
50
|
+
|
|
51
|
+
Add the header `X-Agent-Loop: server` to let litecoo automatically execute multi-step tools server-side before returning the final text to the client.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 💻 Installation
|
|
56
|
+
|
|
57
|
+
To run it locally or use it as a library, install directly from source:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python -m venv venv
|
|
61
|
+
# On Windows: venv\Scripts\activate
|
|
62
|
+
# On Mac/Linux: source venv/bin/activate
|
|
63
|
+
|
|
64
|
+
pip install litecoo
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Then run the proxy:
|
|
68
|
+
```bash
|
|
69
|
+
litecoo --host 0.0.0.0 --port 8000 --env-file .env
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 🔌 Connecting Clients
|
|
73
|
+
|
|
74
|
+
**Claude Desktop:**
|
|
75
|
+
Settings → Developer → API base URL → `http://localhost:8000`
|
|
76
|
+
|
|
77
|
+
**Claude Code:**
|
|
78
|
+
```bash
|
|
79
|
+
export ANTHROPIC_BASE_URL=http://localhost:8000
|
|
80
|
+
export ANTHROPIC_API_KEY=any-string
|
|
81
|
+
claude
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## ⬆️ How to Publish to PyPI
|
|
85
|
+
|
|
86
|
+
If you are a developer and want to push the latest changes to PyPI, follow these steps:
|
|
87
|
+
|
|
88
|
+
1. **Install build tools:**
|
|
89
|
+
```bash
|
|
90
|
+
pip install build twine
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
2. **Build the wheel and source distribution:**
|
|
94
|
+
```bash
|
|
95
|
+
python -m build
|
|
96
|
+
```
|
|
97
|
+
*This creates a `dist/` directory with a `.tar.gz` and `.whl` file.*
|
|
98
|
+
|
|
99
|
+
3. **Upload to PyPI:**
|
|
100
|
+
```bash
|
|
101
|
+
python -m twine upload dist/*
|
|
102
|
+
```
|
|
103
|
+
*You will be prompted for your PyPI API token (username `__token__`).*
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# coworkforvas — model routing config
|
|
2
|
+
# Primary : DeepSeek V4 Flash Free via OpenCodeZen (verified working)
|
|
3
|
+
# Fallback 1: NVIDIA Nemotron 550B via OpenRouter (verified working)
|
|
4
|
+
# Fallback 2: Google Gemma 4 26B via OpenRouter (verified working)
|
|
5
|
+
# Standby : Gemini 2.5 Flash — DISABLED (credits depleted, re-enable when topped up)
|
|
6
|
+
|
|
7
|
+
model_list:
|
|
8
|
+
- model_name: free-default
|
|
9
|
+
provider_params:
|
|
10
|
+
model: openai/deepseek-v4-flash-free
|
|
11
|
+
api_base: https://opencode.ai/zen/v1
|
|
12
|
+
api_key: os.environ/OPENCODEZEN_API_KEY
|
|
13
|
+
extra_headers:
|
|
14
|
+
x-api-key: os.environ/OPENCODEZEN_API_KEY
|
|
15
|
+
User-Agent: "Mozilla/5.0"
|
|
16
|
+
|
|
17
|
+
- model_name: free-openrouter-nemotron
|
|
18
|
+
provider_params:
|
|
19
|
+
model: openrouter/nvidia/nemotron-3-ultra-550b-a55b:free
|
|
20
|
+
api_key: os.environ/OPENROUTER_API_KEY
|
|
21
|
+
|
|
22
|
+
- model_name: free-openrouter-gemma26b
|
|
23
|
+
provider_params:
|
|
24
|
+
model: openrouter/google/gemma-4-26b-a4b-it:free
|
|
25
|
+
api_key: os.environ/OPENROUTER_API_KEY
|
|
26
|
+
|
|
27
|
+
# Uncomment when Gemini credits are topped up at https://ai.studio/projects
|
|
28
|
+
# - model_name: free-gemini-flash
|
|
29
|
+
# provider_params:
|
|
30
|
+
# model: openai/gemini-2.5-flash
|
|
31
|
+
# api_base: https://generativelanguage.googleapis.com/v1beta/openai/
|
|
32
|
+
# api_key: os.environ/GEMINI_API_KEY
|
|
File without changes
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "litecoo"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Free LLM proxy for Cowork and OpenAI-compatible clients — no litellm, pure httpx routing"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
keywords = ["llm", "proxy", "cowork", "openai", "anthropic", "free", "litecoo"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: MIT License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Topic :: Internet :: WWW/HTTP :: HTTP Servers",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"fastapi>=0.128.0,<0.129.0",
|
|
25
|
+
"uvicorn>=0.40.0,<0.41.0",
|
|
26
|
+
"pyyaml>=6.0.1",
|
|
27
|
+
"pydantic>=2.12.3",
|
|
28
|
+
"httpx>=0.27.0",
|
|
29
|
+
"aiosqlite>=0.20.0",
|
|
30
|
+
"python-dotenv>=1.0.0",
|
|
31
|
+
"python-docx>=1.1.0",
|
|
32
|
+
"python-pptx>=0.6.23",
|
|
33
|
+
"openpyxl>=3.1.2",
|
|
34
|
+
"reportlab>=4.1.0",
|
|
35
|
+
"chromadb>=0.5.0",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.optional-dependencies]
|
|
39
|
+
dev = ["pytest", "pytest-asyncio", "httpx"]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
litecoo = "litecoo.cli:main"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/Saisharathchandranandnetha/KrishiMitra_Beast"
|
|
46
|
+
Repository = "https://github.com/Saisharathchandranandnetha/KrishiMitra_Beast"
|
|
47
|
+
|
|
48
|
+
[tool.hatch.build.targets.wheel]
|
|
49
|
+
packages = ["src/litecoo"]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
pythonpath = ["src"]
|
|
53
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[]
|
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Server-side agentic loop for litecoo.
|
|
3
|
+
When X-Agent-Loop: server header is set on /v1/messages requests,
|
|
4
|
+
litecoo executes tool calls internally instead of returning them to the client.
|
|
5
|
+
The loop continues until stop_reason=end_turn or max_turns is reached.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger("litecoo.agent_loop")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def run_agent_loop(
|
|
15
|
+
initial_messages: list[dict],
|
|
16
|
+
system: str,
|
|
17
|
+
tools: list[dict],
|
|
18
|
+
kwargs: dict,
|
|
19
|
+
alias: str,
|
|
20
|
+
router: Any,
|
|
21
|
+
session_id: str = None,
|
|
22
|
+
max_turns: int = 10,
|
|
23
|
+
execute_tool_fn: Optional[Any] = None,
|
|
24
|
+
) -> dict:
|
|
25
|
+
"""
|
|
26
|
+
Execute the agentic tool loop server-side.
|
|
27
|
+
Returns a final Anthropic-format response dict.
|
|
28
|
+
"""
|
|
29
|
+
from .main import openai_response_to_anthropic # late import to avoid circular
|
|
30
|
+
|
|
31
|
+
messages = list(initial_messages)
|
|
32
|
+
|
|
33
|
+
# Ensure system message is prepended if not already present
|
|
34
|
+
if system and (not messages or messages[0].get("role") != "system"):
|
|
35
|
+
messages = [{"role": "system", "content": system}] + messages
|
|
36
|
+
|
|
37
|
+
last_anthropic_resp: dict = {}
|
|
38
|
+
|
|
39
|
+
for turn in range(max_turns):
|
|
40
|
+
call_kwargs = dict(kwargs)
|
|
41
|
+
call_kwargs["messages"] = messages
|
|
42
|
+
call_kwargs["stream"] = False
|
|
43
|
+
if tools:
|
|
44
|
+
call_kwargs["tools"] = tools
|
|
45
|
+
|
|
46
|
+
oai_resp = await router.acompletion(model=alias, **call_kwargs)
|
|
47
|
+
raw = oai_resp.model_dump() if hasattr(oai_resp, "model_dump") else dict(oai_resp)
|
|
48
|
+
|
|
49
|
+
# Determine request_model from alias for response
|
|
50
|
+
anthropic_resp = openai_response_to_anthropic(raw, alias)
|
|
51
|
+
last_anthropic_resp = anthropic_resp
|
|
52
|
+
stop_reason = anthropic_resp.get("stop_reason", "end_turn")
|
|
53
|
+
|
|
54
|
+
if stop_reason == "end_turn":
|
|
55
|
+
logger.info(f"[agent_loop] done after {turn + 1} turn(s)")
|
|
56
|
+
return anthropic_resp
|
|
57
|
+
|
|
58
|
+
if stop_reason == "max_tokens":
|
|
59
|
+
logger.info(f"[agent_loop] max_tokens hit at turn {turn + 1}")
|
|
60
|
+
return anthropic_resp
|
|
61
|
+
|
|
62
|
+
if stop_reason == "tool_use":
|
|
63
|
+
# Build the assistant message from the OAI response
|
|
64
|
+
choice = (raw.get("choices") or [{}])[0]
|
|
65
|
+
asst_msg = choice.get("message", {})
|
|
66
|
+
if hasattr(asst_msg, "model_dump"):
|
|
67
|
+
asst_msg = asst_msg.model_dump()
|
|
68
|
+
messages.append({"role": "assistant", **asst_msg})
|
|
69
|
+
|
|
70
|
+
# Execute each tool and append results to messages in OpenAI format
|
|
71
|
+
for block in anthropic_resp.get("content", []):
|
|
72
|
+
if block.get("type") != "tool_use":
|
|
73
|
+
continue
|
|
74
|
+
tool_name = block.get("name", "")
|
|
75
|
+
tool_input = block.get("input", {})
|
|
76
|
+
tool_id = block.get("id", "")
|
|
77
|
+
|
|
78
|
+
logger.info(f"[agent_loop] executing tool '{tool_name}' (turn {turn + 1})")
|
|
79
|
+
|
|
80
|
+
if "_error_invalid_json" in tool_input:
|
|
81
|
+
error_msg = tool_input["_error_invalid_json"]
|
|
82
|
+
raw_args = tool_input.get("raw_arguments", "")
|
|
83
|
+
result = f"Error: Invalid JSON arguments for tool '{tool_name}'. {error_msg}. Raw input was: {raw_args}. Please correct the JSON syntax and try again."
|
|
84
|
+
else:
|
|
85
|
+
fn = execute_tool_fn if execute_tool_fn else (lambda n, i, sid: __import__("tools").execute_tool(n, i, sid))
|
|
86
|
+
import inspect
|
|
87
|
+
sig = inspect.signature(fn)
|
|
88
|
+
if "session_id" in sig.parameters:
|
|
89
|
+
result = await fn(tool_name, tool_input, session_id=session_id)
|
|
90
|
+
else:
|
|
91
|
+
result = await fn(tool_name, tool_input)
|
|
92
|
+
|
|
93
|
+
messages.append({
|
|
94
|
+
"role": "tool",
|
|
95
|
+
"tool_call_id": tool_id,
|
|
96
|
+
"content": str(result),
|
|
97
|
+
})
|
|
98
|
+
continue
|
|
99
|
+
|
|
100
|
+
# Unknown stop reason — return what we have
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
# max_turns exceeded — annotate and return
|
|
104
|
+
logger.warning(f"[agent_loop] max_turns ({max_turns}) exceeded")
|
|
105
|
+
if last_anthropic_resp:
|
|
106
|
+
last_anthropic_resp["stop_reason"] = "end_turn"
|
|
107
|
+
return last_anthropic_resp
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import sys
|
|
3
|
+
import uvicorn
|
|
4
|
+
|
|
5
|
+
def main():
|
|
6
|
+
parser = argparse.ArgumentParser(description="litecoo - Free LLM proxy for Cowork")
|
|
7
|
+
parser.add_argument("--host", default="0.0.0.0", help="Host to bind (default: 0.0.0.0)")
|
|
8
|
+
parser.add_argument("--port", type=int, default=8000, help="Port to bind (default: 8000)")
|
|
9
|
+
parser.add_argument("--env-file", default=".env", help="Environment file to load")
|
|
10
|
+
|
|
11
|
+
args = parser.parse_args()
|
|
12
|
+
|
|
13
|
+
# We pass the import string instead of the object to enable hot-reloading if needed,
|
|
14
|
+
# and to ensure uvicorn runs correctly across platforms.
|
|
15
|
+
uvicorn.run("litecoo.main:app", host=args.host, port=args.port, env_file=args.env_file)
|
|
16
|
+
|
|
17
|
+
if __name__ == "__main__":
|
|
18
|
+
main()
|