zerochat 7.11.0__tar.gz → 8.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.
- zerochat-8.0.0/PKG-INFO +101 -0
- zerochat-8.0.0/README.md +79 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/pyproject.toml +1 -1
- zerochat-8.0.0/zerochat.egg-info/PKG-INFO +101 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/zerochat.py +231 -124
- zerochat-7.11.0/PKG-INFO +0 -72
- zerochat-7.11.0/README.md +0 -50
- zerochat-7.11.0/zerochat.egg-info/PKG-INFO +0 -72
- {zerochat-7.11.0 → zerochat-8.0.0}/LICENSE +0 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/setup.cfg +0 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/zerochat.egg-info/SOURCES.txt +0 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/zerochat.egg-info/dependency_links.txt +0 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/zerochat.egg-info/entry_points.txt +0 -0
- {zerochat-7.11.0 → zerochat-8.0.0}/zerochat.egg-info/top_level.txt +0 -0
zerochat-8.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zerochat
|
|
3
|
+
Version: 8.0.0
|
|
4
|
+
Summary: Private local web client for AI models, tools and MCP services
|
|
5
|
+
Author: Alberto Alday
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://albalday.github.io/zerochat/
|
|
8
|
+
Project-URL: Repository, https://github.com/albalday/zerochat
|
|
9
|
+
Project-URL: Issues, https://github.com/albalday/zerochat/issues
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# ZeroChat
|
|
24
|
+
|
|
25
|
+
ZeroChat es un cliente web de uso personal para conversar con modelos de IA, consultar documentos y utilizar herramientas. Esta documentación corresponde a la serie **8.x**, que consolida las funcionalidades existentes. El desarrollo de nuevas funcionalidades queda en pausa por el momento.
|
|
26
|
+
|
|
27
|
+
La interfaz se sirve como archivos estáticos: `zerochat.html` necesita sus módulos `js/` y `css/`. El historial y la configuración se guardan en el navegador; no se sincronizan automáticamente entre dispositivos. Los proveedores remotos reciben el contenido incluido en las peticiones, y las herramientas web pueden utilizar servicios intermediarios. Almacenamiento local no significa privacidad absoluta.
|
|
28
|
+
|
|
29
|
+
*English:* ZeroChat is a web client for personal use: chatting with AI models, consulting documents and using tools. This documentation covers the **8.x** series, which consolidates existing features. New feature development is paused for now.
|
|
30
|
+
|
|
31
|
+
The interface is served as static files: `zerochat.html` needs its `js/` and `css/` modules. History and settings are stored in the browser, without automatic cross-device sync. Remote providers receive content included in requests, and web tools may use intermediary services. Local storage does not mean absolute privacy.
|
|
32
|
+
|
|
33
|
+
## Características principales / Main features
|
|
34
|
+
|
|
35
|
+
- **Perfiles:** OpenAI y APIs de chat compatibles, Ollama, OpenRouter, Claude y Gemini. La visión, las herramientas y el razonamiento dependen del modelo y del adaptador.
|
|
36
|
+
- **WebLLM:** inferencia en el navegador con WebGPU, tras descargar un modelo. Necesita hardware compatible y memoria suficiente.
|
|
37
|
+
- **Documentos:** adjuntos y colecciones RAG con extracción local y búsqueda léxica mediante Orama; sin embeddings. Los fragmentos recuperados se envían al modelo elegido. La extracción de PDF tiene límites y no incluye OCR general.
|
|
38
|
+
- **Herramientas:** JavaScript aislado, búsqueda y lectura web, gráficos, planes y puntos de control. El backend opcional añade archivos, comandos, diagnósticos, automatización de navegador y servicios MCP.
|
|
39
|
+
- **Historial y diagnóstico:** ramas de conversación, exportación JSON y Markdown, impresión a PDF, métricas de contexto y revisión de peticiones antes del envío.
|
|
40
|
+
|
|
41
|
+
*English:*
|
|
42
|
+
|
|
43
|
+
- **Profiles:** OpenAI and compatible chat APIs, Ollama, OpenRouter, Claude and Gemini. Vision, tools and reasoning depend on the model and adapter.
|
|
44
|
+
- **WebLLM:** browser inference through WebGPU after downloading a model. Requires compatible hardware and enough memory.
|
|
45
|
+
- **Documents:** attachments and RAG collections with local extraction and Orama lexical search, without embeddings. Retrieved passages are sent to the selected model. PDF extraction has limitations and no general OCR.
|
|
46
|
+
- **Tools:** isolated JavaScript, web search and retrieval, charts, plans and checkpoints. The optional backend adds files, commands, diagnostics, browser automation and MCP services.
|
|
47
|
+
- **History and diagnostics:** conversation branches, JSON and Markdown export, printing to PDF, context metrics and request inspection before sending.
|
|
48
|
+
|
|
49
|
+
## Inicio rápido / Quick start
|
|
50
|
+
|
|
51
|
+
Abre [ZeroChat en GitHub Pages](https://albalday.github.io/zerochat/zerochat.html), crea un perfil, introduce la URL y la clave si corresponde, consulta los modelos con **Query** y guarda. El perfil **Espejo** permite probar la interfaz sin inferencia. Para WebLLM, prepara un modelo del catálogo.
|
|
52
|
+
|
|
53
|
+
*English:* Open [ZeroChat on GitHub Pages](https://albalday.github.io/zerochat/zerochat.html), create a profile, enter the URL and key where required, query models with **Query**, and save. **Mirror** lets you try the interface without inference. For WebLLM, prepare a catalogue model.
|
|
54
|
+
|
|
55
|
+
Para añadir herramientas del equipo, instala y ejecuta el backend con Python. / To add computer tools, install and run the Python backend:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install zerochat
|
|
59
|
+
zerochat
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
También puedes descargar el script y ejecutarlo. / You can also download and run the script:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
curl -sL https://albalday.github.io/zerochat/zerochat.py -o zerochat.py
|
|
66
|
+
python3 zerochat.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Fuera del repositorio de desarrollo, ambos modos abren la interfaz de GitHub Pages. Crean `~/zerochat/` para configuración y servicios, con `.venv/` para dependencias MCP Python. Mantén el proceso abierto y usa su enlace de arranque para autenticar la conexión local. Revisa **Ajustes → MCP** y **Permisos** antes de habilitar herramientas: los comandos actúan con los permisos del proceso local y detenerlos no deshace cambios.
|
|
70
|
+
|
|
71
|
+
Borrar `~/zerochat/` elimina ese estado y los MCP gestionados, no el ejecutable, los archivos modificados fuera de esa carpeta ni los datos del navegador. Exporta las conversaciones y perfiles que quieras conservar; sus copias no incluyen las colecciones RAG ni los modelos descargados. El cifrado predeterminado de perfiles utiliza una clave integrada conocida: trata las copias como archivos sensibles.
|
|
72
|
+
|
|
73
|
+
*English:* Outside the development repository, both modes open the GitHub Pages interface. They create `~/zerochat/` for configuration and services, with `.venv/` for Python MCP dependencies. Keep the process running and use its startup link to authenticate the local connection. Review **Settings → MCP** and **Permissions** before enabling tools: commands run with the local process permissions, and stopping them does not undo changes.
|
|
74
|
+
|
|
75
|
+
Deleting `~/zerochat/` removes that state and managed MCP services, not the executable, files changed elsewhere or browser data. Export conversations and profiles you want to keep; these backups do not include RAG collections or downloaded models. Default profile encryption uses a known built-in key: treat backups as sensitive files.
|
|
76
|
+
|
|
77
|
+
## Documentación y ayuda / Documentation and help
|
|
78
|
+
|
|
79
|
+
- [Ayuda de ZeroChat 8.x — Español](https://albalday.github.io/zerochat/help/index.html)
|
|
80
|
+
- [ZeroChat 8.x help — English](https://albalday.github.io/zerochat/help/en/index.html)
|
|
81
|
+
|
|
82
|
+
Las guías explican configuración, uso y límites. Los informes conservan su versión y fecha de revisión originales; no son una certificación de 8.x ni una promesa de nuevas funcionalidades.
|
|
83
|
+
|
|
84
|
+
*English:* The guides explain setup, usage and limits. Reports retain their original reviewed version and date; they are not an 8.x certification or a promise of new features.
|
|
85
|
+
|
|
86
|
+
## Desarrollo / Development
|
|
87
|
+
|
|
88
|
+
Trabaja en `dev`. Para instalar dependencias y ejecutar las pruebas del proyecto: / Work on `dev`. To install dependencies and run the project tests:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install
|
|
92
|
+
npm test
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Dentro del repositorio, `python3 zerochat.py` sirve la interfaz local de desarrollo. Si modificas `py/`, reconstruye `zerochat.py` con `npm run build:backend`. La web carga directamente sus módulos, sin un bundle de aplicación.
|
|
96
|
+
|
|
97
|
+
*English:* Inside the repository, `python3 zerochat.py` serves the local development interface. After changing `py/`, rebuild `zerochat.py` with `npm run build:backend`. The web app loads its modules directly, without an application bundle.
|
|
98
|
+
|
|
99
|
+
Las normas y validaciones se describen en [`AGENTS.md`](./AGENTS.md) y [`tests/README.md`](./tests/README.md).
|
|
100
|
+
|
|
101
|
+
*English:* See those files for the applicable development rules and validation.
|
zerochat-8.0.0/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# ZeroChat
|
|
2
|
+
|
|
3
|
+
ZeroChat es un cliente web de uso personal para conversar con modelos de IA, consultar documentos y utilizar herramientas. Esta documentación corresponde a la serie **8.x**, que consolida las funcionalidades existentes. El desarrollo de nuevas funcionalidades queda en pausa por el momento.
|
|
4
|
+
|
|
5
|
+
La interfaz se sirve como archivos estáticos: `zerochat.html` necesita sus módulos `js/` y `css/`. El historial y la configuración se guardan en el navegador; no se sincronizan automáticamente entre dispositivos. Los proveedores remotos reciben el contenido incluido en las peticiones, y las herramientas web pueden utilizar servicios intermediarios. Almacenamiento local no significa privacidad absoluta.
|
|
6
|
+
|
|
7
|
+
*English:* ZeroChat is a web client for personal use: chatting with AI models, consulting documents and using tools. This documentation covers the **8.x** series, which consolidates existing features. New feature development is paused for now.
|
|
8
|
+
|
|
9
|
+
The interface is served as static files: `zerochat.html` needs its `js/` and `css/` modules. History and settings are stored in the browser, without automatic cross-device sync. Remote providers receive content included in requests, and web tools may use intermediary services. Local storage does not mean absolute privacy.
|
|
10
|
+
|
|
11
|
+
## Características principales / Main features
|
|
12
|
+
|
|
13
|
+
- **Perfiles:** OpenAI y APIs de chat compatibles, Ollama, OpenRouter, Claude y Gemini. La visión, las herramientas y el razonamiento dependen del modelo y del adaptador.
|
|
14
|
+
- **WebLLM:** inferencia en el navegador con WebGPU, tras descargar un modelo. Necesita hardware compatible y memoria suficiente.
|
|
15
|
+
- **Documentos:** adjuntos y colecciones RAG con extracción local y búsqueda léxica mediante Orama; sin embeddings. Los fragmentos recuperados se envían al modelo elegido. La extracción de PDF tiene límites y no incluye OCR general.
|
|
16
|
+
- **Herramientas:** JavaScript aislado, búsqueda y lectura web, gráficos, planes y puntos de control. El backend opcional añade archivos, comandos, diagnósticos, automatización de navegador y servicios MCP.
|
|
17
|
+
- **Historial y diagnóstico:** ramas de conversación, exportación JSON y Markdown, impresión a PDF, métricas de contexto y revisión de peticiones antes del envío.
|
|
18
|
+
|
|
19
|
+
*English:*
|
|
20
|
+
|
|
21
|
+
- **Profiles:** OpenAI and compatible chat APIs, Ollama, OpenRouter, Claude and Gemini. Vision, tools and reasoning depend on the model and adapter.
|
|
22
|
+
- **WebLLM:** browser inference through WebGPU after downloading a model. Requires compatible hardware and enough memory.
|
|
23
|
+
- **Documents:** attachments and RAG collections with local extraction and Orama lexical search, without embeddings. Retrieved passages are sent to the selected model. PDF extraction has limitations and no general OCR.
|
|
24
|
+
- **Tools:** isolated JavaScript, web search and retrieval, charts, plans and checkpoints. The optional backend adds files, commands, diagnostics, browser automation and MCP services.
|
|
25
|
+
- **History and diagnostics:** conversation branches, JSON and Markdown export, printing to PDF, context metrics and request inspection before sending.
|
|
26
|
+
|
|
27
|
+
## Inicio rápido / Quick start
|
|
28
|
+
|
|
29
|
+
Abre [ZeroChat en GitHub Pages](https://albalday.github.io/zerochat/zerochat.html), crea un perfil, introduce la URL y la clave si corresponde, consulta los modelos con **Query** y guarda. El perfil **Espejo** permite probar la interfaz sin inferencia. Para WebLLM, prepara un modelo del catálogo.
|
|
30
|
+
|
|
31
|
+
*English:* Open [ZeroChat on GitHub Pages](https://albalday.github.io/zerochat/zerochat.html), create a profile, enter the URL and key where required, query models with **Query**, and save. **Mirror** lets you try the interface without inference. For WebLLM, prepare a catalogue model.
|
|
32
|
+
|
|
33
|
+
Para añadir herramientas del equipo, instala y ejecuta el backend con Python. / To add computer tools, install and run the Python backend:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install zerochat
|
|
37
|
+
zerochat
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
También puedes descargar el script y ejecutarlo. / You can also download and run the script:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
curl -sL https://albalday.github.io/zerochat/zerochat.py -o zerochat.py
|
|
44
|
+
python3 zerochat.py
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Fuera del repositorio de desarrollo, ambos modos abren la interfaz de GitHub Pages. Crean `~/zerochat/` para configuración y servicios, con `.venv/` para dependencias MCP Python. Mantén el proceso abierto y usa su enlace de arranque para autenticar la conexión local. Revisa **Ajustes → MCP** y **Permisos** antes de habilitar herramientas: los comandos actúan con los permisos del proceso local y detenerlos no deshace cambios.
|
|
48
|
+
|
|
49
|
+
Borrar `~/zerochat/` elimina ese estado y los MCP gestionados, no el ejecutable, los archivos modificados fuera de esa carpeta ni los datos del navegador. Exporta las conversaciones y perfiles que quieras conservar; sus copias no incluyen las colecciones RAG ni los modelos descargados. El cifrado predeterminado de perfiles utiliza una clave integrada conocida: trata las copias como archivos sensibles.
|
|
50
|
+
|
|
51
|
+
*English:* Outside the development repository, both modes open the GitHub Pages interface. They create `~/zerochat/` for configuration and services, with `.venv/` for Python MCP dependencies. Keep the process running and use its startup link to authenticate the local connection. Review **Settings → MCP** and **Permissions** before enabling tools: commands run with the local process permissions, and stopping them does not undo changes.
|
|
52
|
+
|
|
53
|
+
Deleting `~/zerochat/` removes that state and managed MCP services, not the executable, files changed elsewhere or browser data. Export conversations and profiles you want to keep; these backups do not include RAG collections or downloaded models. Default profile encryption uses a known built-in key: treat backups as sensitive files.
|
|
54
|
+
|
|
55
|
+
## Documentación y ayuda / Documentation and help
|
|
56
|
+
|
|
57
|
+
- [Ayuda de ZeroChat 8.x — Español](https://albalday.github.io/zerochat/help/index.html)
|
|
58
|
+
- [ZeroChat 8.x help — English](https://albalday.github.io/zerochat/help/en/index.html)
|
|
59
|
+
|
|
60
|
+
Las guías explican configuración, uso y límites. Los informes conservan su versión y fecha de revisión originales; no son una certificación de 8.x ni una promesa de nuevas funcionalidades.
|
|
61
|
+
|
|
62
|
+
*English:* The guides explain setup, usage and limits. Reports retain their original reviewed version and date; they are not an 8.x certification or a promise of new features.
|
|
63
|
+
|
|
64
|
+
## Desarrollo / Development
|
|
65
|
+
|
|
66
|
+
Trabaja en `dev`. Para instalar dependencias y ejecutar las pruebas del proyecto: / Work on `dev`. To install dependencies and run the project tests:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install
|
|
70
|
+
npm test
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Dentro del repositorio, `python3 zerochat.py` sirve la interfaz local de desarrollo. Si modificas `py/`, reconstruye `zerochat.py` con `npm run build:backend`. La web carga directamente sus módulos, sin un bundle de aplicación.
|
|
74
|
+
|
|
75
|
+
*English:* Inside the repository, `python3 zerochat.py` serves the local development interface. After changing `py/`, rebuild `zerochat.py` with `npm run build:backend`. The web app loads its modules directly, without an application bundle.
|
|
76
|
+
|
|
77
|
+
Las normas y validaciones se describen en [`AGENTS.md`](./AGENTS.md) y [`tests/README.md`](./tests/README.md).
|
|
78
|
+
|
|
79
|
+
*English:* See those files for the applicable development rules and validation.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: zerochat
|
|
3
|
+
Version: 8.0.0
|
|
4
|
+
Summary: Private local web client for AI models, tools and MCP services
|
|
5
|
+
Author: Alberto Alday
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://albalday.github.io/zerochat/
|
|
8
|
+
Project-URL: Repository, https://github.com/albalday/zerochat
|
|
9
|
+
Project-URL: Issues, https://github.com/albalday/zerochat/issues
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Web Environment
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# ZeroChat
|
|
24
|
+
|
|
25
|
+
ZeroChat es un cliente web de uso personal para conversar con modelos de IA, consultar documentos y utilizar herramientas. Esta documentación corresponde a la serie **8.x**, que consolida las funcionalidades existentes. El desarrollo de nuevas funcionalidades queda en pausa por el momento.
|
|
26
|
+
|
|
27
|
+
La interfaz se sirve como archivos estáticos: `zerochat.html` necesita sus módulos `js/` y `css/`. El historial y la configuración se guardan en el navegador; no se sincronizan automáticamente entre dispositivos. Los proveedores remotos reciben el contenido incluido en las peticiones, y las herramientas web pueden utilizar servicios intermediarios. Almacenamiento local no significa privacidad absoluta.
|
|
28
|
+
|
|
29
|
+
*English:* ZeroChat is a web client for personal use: chatting with AI models, consulting documents and using tools. This documentation covers the **8.x** series, which consolidates existing features. New feature development is paused for now.
|
|
30
|
+
|
|
31
|
+
The interface is served as static files: `zerochat.html` needs its `js/` and `css/` modules. History and settings are stored in the browser, without automatic cross-device sync. Remote providers receive content included in requests, and web tools may use intermediary services. Local storage does not mean absolute privacy.
|
|
32
|
+
|
|
33
|
+
## Características principales / Main features
|
|
34
|
+
|
|
35
|
+
- **Perfiles:** OpenAI y APIs de chat compatibles, Ollama, OpenRouter, Claude y Gemini. La visión, las herramientas y el razonamiento dependen del modelo y del adaptador.
|
|
36
|
+
- **WebLLM:** inferencia en el navegador con WebGPU, tras descargar un modelo. Necesita hardware compatible y memoria suficiente.
|
|
37
|
+
- **Documentos:** adjuntos y colecciones RAG con extracción local y búsqueda léxica mediante Orama; sin embeddings. Los fragmentos recuperados se envían al modelo elegido. La extracción de PDF tiene límites y no incluye OCR general.
|
|
38
|
+
- **Herramientas:** JavaScript aislado, búsqueda y lectura web, gráficos, planes y puntos de control. El backend opcional añade archivos, comandos, diagnósticos, automatización de navegador y servicios MCP.
|
|
39
|
+
- **Historial y diagnóstico:** ramas de conversación, exportación JSON y Markdown, impresión a PDF, métricas de contexto y revisión de peticiones antes del envío.
|
|
40
|
+
|
|
41
|
+
*English:*
|
|
42
|
+
|
|
43
|
+
- **Profiles:** OpenAI and compatible chat APIs, Ollama, OpenRouter, Claude and Gemini. Vision, tools and reasoning depend on the model and adapter.
|
|
44
|
+
- **WebLLM:** browser inference through WebGPU after downloading a model. Requires compatible hardware and enough memory.
|
|
45
|
+
- **Documents:** attachments and RAG collections with local extraction and Orama lexical search, without embeddings. Retrieved passages are sent to the selected model. PDF extraction has limitations and no general OCR.
|
|
46
|
+
- **Tools:** isolated JavaScript, web search and retrieval, charts, plans and checkpoints. The optional backend adds files, commands, diagnostics, browser automation and MCP services.
|
|
47
|
+
- **History and diagnostics:** conversation branches, JSON and Markdown export, printing to PDF, context metrics and request inspection before sending.
|
|
48
|
+
|
|
49
|
+
## Inicio rápido / Quick start
|
|
50
|
+
|
|
51
|
+
Abre [ZeroChat en GitHub Pages](https://albalday.github.io/zerochat/zerochat.html), crea un perfil, introduce la URL y la clave si corresponde, consulta los modelos con **Query** y guarda. El perfil **Espejo** permite probar la interfaz sin inferencia. Para WebLLM, prepara un modelo del catálogo.
|
|
52
|
+
|
|
53
|
+
*English:* Open [ZeroChat on GitHub Pages](https://albalday.github.io/zerochat/zerochat.html), create a profile, enter the URL and key where required, query models with **Query**, and save. **Mirror** lets you try the interface without inference. For WebLLM, prepare a catalogue model.
|
|
54
|
+
|
|
55
|
+
Para añadir herramientas del equipo, instala y ejecuta el backend con Python. / To add computer tools, install and run the Python backend:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install zerochat
|
|
59
|
+
zerochat
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
También puedes descargar el script y ejecutarlo. / You can also download and run the script:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
curl -sL https://albalday.github.io/zerochat/zerochat.py -o zerochat.py
|
|
66
|
+
python3 zerochat.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Fuera del repositorio de desarrollo, ambos modos abren la interfaz de GitHub Pages. Crean `~/zerochat/` para configuración y servicios, con `.venv/` para dependencias MCP Python. Mantén el proceso abierto y usa su enlace de arranque para autenticar la conexión local. Revisa **Ajustes → MCP** y **Permisos** antes de habilitar herramientas: los comandos actúan con los permisos del proceso local y detenerlos no deshace cambios.
|
|
70
|
+
|
|
71
|
+
Borrar `~/zerochat/` elimina ese estado y los MCP gestionados, no el ejecutable, los archivos modificados fuera de esa carpeta ni los datos del navegador. Exporta las conversaciones y perfiles que quieras conservar; sus copias no incluyen las colecciones RAG ni los modelos descargados. El cifrado predeterminado de perfiles utiliza una clave integrada conocida: trata las copias como archivos sensibles.
|
|
72
|
+
|
|
73
|
+
*English:* Outside the development repository, both modes open the GitHub Pages interface. They create `~/zerochat/` for configuration and services, with `.venv/` for Python MCP dependencies. Keep the process running and use its startup link to authenticate the local connection. Review **Settings → MCP** and **Permissions** before enabling tools: commands run with the local process permissions, and stopping them does not undo changes.
|
|
74
|
+
|
|
75
|
+
Deleting `~/zerochat/` removes that state and managed MCP services, not the executable, files changed elsewhere or browser data. Export conversations and profiles you want to keep; these backups do not include RAG collections or downloaded models. Default profile encryption uses a known built-in key: treat backups as sensitive files.
|
|
76
|
+
|
|
77
|
+
## Documentación y ayuda / Documentation and help
|
|
78
|
+
|
|
79
|
+
- [Ayuda de ZeroChat 8.x — Español](https://albalday.github.io/zerochat/help/index.html)
|
|
80
|
+
- [ZeroChat 8.x help — English](https://albalday.github.io/zerochat/help/en/index.html)
|
|
81
|
+
|
|
82
|
+
Las guías explican configuración, uso y límites. Los informes conservan su versión y fecha de revisión originales; no son una certificación de 8.x ni una promesa de nuevas funcionalidades.
|
|
83
|
+
|
|
84
|
+
*English:* The guides explain setup, usage and limits. Reports retain their original reviewed version and date; they are not an 8.x certification or a promise of new features.
|
|
85
|
+
|
|
86
|
+
## Desarrollo / Development
|
|
87
|
+
|
|
88
|
+
Trabaja en `dev`. Para instalar dependencias y ejecutar las pruebas del proyecto: / Work on `dev`. To install dependencies and run the project tests:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install
|
|
92
|
+
npm test
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Dentro del repositorio, `python3 zerochat.py` sirve la interfaz local de desarrollo. Si modificas `py/`, reconstruye `zerochat.py` con `npm run build:backend`. La web carga directamente sus módulos, sin un bundle de aplicación.
|
|
96
|
+
|
|
97
|
+
*English:* Inside the repository, `python3 zerochat.py` serves the local development interface. After changing `py/`, rebuild `zerochat.py` with `npm run build:backend`. The web app loads its modules directly, without an application bundle.
|
|
98
|
+
|
|
99
|
+
Las normas y validaciones se describen en [`AGENTS.md`](./AGENTS.md) y [`tests/README.md`](./tests/README.md).
|
|
100
|
+
|
|
101
|
+
*English:* See those files for the applicable development rules and validation.
|
|
@@ -14,8 +14,10 @@ from __future__ import annotations
|
|
|
14
14
|
import argparse
|
|
15
15
|
import ast
|
|
16
16
|
import atexit
|
|
17
|
+
import base64
|
|
17
18
|
import datetime
|
|
18
19
|
import fnmatch
|
|
20
|
+
import hashlib
|
|
19
21
|
import hmac
|
|
20
22
|
import importlib.metadata
|
|
21
23
|
import json
|
|
@@ -40,7 +42,7 @@ import webbrowser
|
|
|
40
42
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
41
43
|
from pathlib import Path
|
|
42
44
|
|
|
43
|
-
SOURCE_BACKEND_VERSION = "
|
|
45
|
+
SOURCE_BACKEND_VERSION = "8.0.0"
|
|
44
46
|
|
|
45
47
|
def _read_source_version(filename: str) -> str | None:
|
|
46
48
|
"""Lee la versión de un archivo del repositorio cuando se ejecuta desde fuentes."""
|
|
@@ -96,143 +98,97 @@ PYPI_VERSION_URL = "https://pypi.org/pypi/zerochat/json"
|
|
|
96
98
|
REMOTE_SCRIPT_URL = "https://raw.githubusercontent.com/albalday/zerochat/master/zerochat.py"
|
|
97
99
|
CONSOLE_STATUS_IDLE_SECONDS = 8.0
|
|
98
100
|
CONSOLE_CONTROL = None
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def format_uptime(seconds: float) -> str:
|
|
102
|
-
"""Devuelve una duración breve y estable para la línea de estado de consola."""
|
|
103
|
-
total = max(0, int(seconds))
|
|
104
|
-
hours, remainder = divmod(total, 3600)
|
|
105
|
-
minutes, secs = divmod(remainder, 60)
|
|
106
|
-
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
NOTICES: list[str] = []
|
|
102
|
+
NOTICES_LOCK = threading.Lock()
|
|
109
103
|
class ConsoleControl:
|
|
110
|
-
"""
|
|
104
|
+
"""Muestra una sola línea de ayuda tras un periodo de inactividad en consola."""
|
|
111
105
|
def __init__(self, server: ThreadingHTTPServer, parser: argparse.ArgumentParser, target_url: str | None = None):
|
|
112
106
|
self.server = server
|
|
113
107
|
self.parser = parser
|
|
114
108
|
self.target_url = target_url
|
|
115
|
-
self.
|
|
116
|
-
self.last_activity = self.started_at
|
|
117
|
-
self.stop_event = threading.Event()
|
|
109
|
+
self.last_activity = time.monotonic()
|
|
118
110
|
self.lock = threading.Lock()
|
|
119
|
-
self.
|
|
120
|
-
self.
|
|
121
|
-
self.
|
|
122
|
-
self.
|
|
123
|
-
self.
|
|
111
|
+
self.enabled = bool(getattr(sys.stdout, "isatty", lambda: False)())
|
|
112
|
+
self._keyboard_enabled = bool(getattr(sys.stdin, "isatty", lambda: False)())
|
|
113
|
+
self._idle_timer: threading.Timer | None = None
|
|
114
|
+
self._keyboard_stop = threading.Event()
|
|
115
|
+
self._keyboard_thread: threading.Thread | None = None
|
|
116
|
+
self._timer_generation = 0
|
|
124
117
|
self._closed = False
|
|
125
118
|
|
|
126
119
|
def start(self):
|
|
127
|
-
if
|
|
128
|
-
|
|
129
|
-
if
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
import tty
|
|
133
|
-
self._terminal_fd = sys.stdin.fileno()
|
|
134
|
-
self._terminal_state = termios.tcgetattr(self._terminal_fd)
|
|
135
|
-
tty.setcbreak(self._terminal_fd)
|
|
136
|
-
except (OSError, ValueError):
|
|
137
|
-
self._restore_terminal()
|
|
138
|
-
self.enabled = False
|
|
139
|
-
return
|
|
140
|
-
self._threads = [
|
|
141
|
-
threading.Thread(target=self._status_loop, name="zerochat-console-status", daemon=True),
|
|
142
|
-
threading.Thread(target=self._keyboard_loop, name="zerochat-console-input", daemon=True),
|
|
143
|
-
]
|
|
144
|
-
for thread in self._threads:
|
|
145
|
-
thread.start()
|
|
120
|
+
if self.enabled:
|
|
121
|
+
self._reset_idle_timer()
|
|
122
|
+
if self._keyboard_enabled:
|
|
123
|
+
self._keyboard_thread = threading.Thread(target=self._keyboard_loop, name="zerochat-console-input", daemon=True)
|
|
124
|
+
self._keyboard_thread.start()
|
|
146
125
|
|
|
147
126
|
def close(self):
|
|
148
|
-
if self._closed:
|
|
149
|
-
return
|
|
150
|
-
self._closed = True
|
|
151
|
-
self.stop_event.set()
|
|
152
|
-
for thread in self._threads:
|
|
153
|
-
if thread is not threading.current_thread():
|
|
154
|
-
thread.join(timeout=1.0)
|
|
155
|
-
self._restore_terminal()
|
|
156
|
-
self.clear_status(final=True)
|
|
157
|
-
|
|
158
|
-
def _restore_terminal(self):
|
|
159
|
-
if self._terminal_fd is None or self._terminal_state is None:
|
|
160
|
-
return
|
|
161
|
-
try:
|
|
162
|
-
import termios
|
|
163
|
-
termios.tcsetattr(self._terminal_fd, termios.TCSADRAIN, self._terminal_state)
|
|
164
|
-
except OSError:
|
|
165
|
-
pass
|
|
166
|
-
finally:
|
|
167
|
-
self._terminal_fd = None
|
|
168
|
-
self._terminal_state = None
|
|
169
|
-
|
|
170
|
-
def clear_status(self, *, final: bool = False):
|
|
171
|
-
if not self.enabled:
|
|
172
|
-
return
|
|
173
127
|
with self.lock:
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
sys.stdout.flush()
|
|
128
|
+
self._closed = True
|
|
129
|
+
self._keyboard_stop.set()
|
|
130
|
+
if self._idle_timer:
|
|
131
|
+
self._idle_timer.cancel()
|
|
132
|
+
self._idle_timer = None
|
|
180
133
|
|
|
181
|
-
def
|
|
134
|
+
def _reset_idle_timer(self):
|
|
182
135
|
with self.lock:
|
|
183
|
-
if self.
|
|
184
|
-
|
|
185
|
-
self.status_visible = False
|
|
186
|
-
print(message, flush=flush)
|
|
136
|
+
if self._closed:
|
|
137
|
+
return
|
|
187
138
|
self.last_activity = time.monotonic()
|
|
139
|
+
self._timer_generation += 1
|
|
140
|
+
if self._idle_timer:
|
|
141
|
+
self._idle_timer.cancel()
|
|
142
|
+
generation = self._timer_generation
|
|
143
|
+
self._idle_timer = threading.Timer(CONSOLE_STATUS_IDLE_SECONDS, self._show_commands_once, args=(generation,))
|
|
144
|
+
self._idle_timer.daemon = True
|
|
145
|
+
self._idle_timer.start()
|
|
146
|
+
|
|
147
|
+
def _show_commands_once(self, generation: int):
|
|
148
|
+
with self.lock:
|
|
149
|
+
if self._closed or generation != self._timer_generation:
|
|
150
|
+
return
|
|
151
|
+
commands = "[h] ayuda · [n] Navegador"
|
|
152
|
+
if get_notices():
|
|
153
|
+
commands += " · [i] información"
|
|
154
|
+
print(f"Comandos de consola: {commands} · [x] salir ordenadamente", flush=True)
|
|
155
|
+
self._idle_timer = None
|
|
156
|
+
|
|
157
|
+
def log(self, message: str, *, flush: bool = True):
|
|
158
|
+
print(message, flush=flush)
|
|
159
|
+
if self.enabled:
|
|
160
|
+
self._reset_idle_timer()
|
|
188
161
|
|
|
189
162
|
def show_help(self):
|
|
190
|
-
|
|
191
|
-
if self.status_visible:
|
|
192
|
-
sys.stdout.write("\r\033[2K")
|
|
193
|
-
self.status_visible = False
|
|
194
|
-
print("\nComandos de consola: [h] ayuda · [n] Navegador · [x] salir ordenadamente\n", flush=True)
|
|
195
|
-
print(self.parser.format_help().rstrip(), flush=True)
|
|
196
|
-
self.last_activity = time.monotonic()
|
|
163
|
+
print(self.parser.format_help().rstrip(), flush=True)
|
|
197
164
|
|
|
198
|
-
def
|
|
199
|
-
|
|
165
|
+
def show_notices(self):
|
|
166
|
+
notices = get_notices()
|
|
167
|
+
if not notices:
|
|
200
168
|
return
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
return
|
|
205
|
-
sys.stdout.write(f"\r\033[2KZeroChat activo {uptime} · [h] ayuda · [n] Navegador · [x] salir")
|
|
206
|
-
sys.stdout.flush()
|
|
207
|
-
self.status_visible = True
|
|
208
|
-
|
|
209
|
-
def _status_loop(self):
|
|
210
|
-
while not self.stop_event.wait(1.0):
|
|
211
|
-
self._render_status()
|
|
169
|
+
print("Información:", flush=True)
|
|
170
|
+
for notice in notices:
|
|
171
|
+
print(f"- {notice}", flush=True)
|
|
212
172
|
|
|
213
|
-
def
|
|
214
|
-
|
|
173
|
+
def _handle_command(self, command: str):
|
|
174
|
+
key = command.strip().lower()
|
|
175
|
+
if key == "h":
|
|
215
176
|
self.show_help()
|
|
216
|
-
elif key
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
177
|
+
elif key == "n" and self.target_url:
|
|
178
|
+
launch_browser(self.target_url)
|
|
179
|
+
elif key == "i":
|
|
180
|
+
self.show_notices()
|
|
181
|
+
elif key == "x":
|
|
220
182
|
self.log(f"[{time.strftime('%H:%M:%S')}] Deteniendo servidor ZeroChat...")
|
|
221
183
|
stop_zerochat_server(self.server)
|
|
222
184
|
|
|
223
185
|
def _keyboard_loop(self):
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
import select
|
|
232
|
-
while not self.stop_event.is_set():
|
|
233
|
-
ready, _, _ = select.select([sys.stdin], [], [], 0.1)
|
|
234
|
-
if ready:
|
|
235
|
-
self._handle_key(sys.stdin.read(1))
|
|
186
|
+
"""Lee comandos normales terminados con Intro, sin alterar el terminal."""
|
|
187
|
+
while not self._keyboard_stop.is_set():
|
|
188
|
+
line = sys.stdin.readline()
|
|
189
|
+
if not line:
|
|
190
|
+
return
|
|
191
|
+
self._handle_command(line)
|
|
236
192
|
|
|
237
193
|
|
|
238
194
|
def console_log(message: str, *, flush: bool = True):
|
|
@@ -282,6 +238,26 @@ def get_venv_dir() -> Path:
|
|
|
282
238
|
return get_data_dir() / ".venv"
|
|
283
239
|
|
|
284
240
|
|
|
241
|
+
def reset_notices():
|
|
242
|
+
"""Reinicia los avisos transitorios de la ejecución actual."""
|
|
243
|
+
with NOTICES_LOCK:
|
|
244
|
+
NOTICES.clear()
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def add_notice(message: str):
|
|
248
|
+
"""Añade un aviso para la consola interactiva de la ejecución actual."""
|
|
249
|
+
if not isinstance(message, str) or not message.strip():
|
|
250
|
+
raise ValueError("El aviso debe ser texto no vacío")
|
|
251
|
+
with NOTICES_LOCK:
|
|
252
|
+
NOTICES.append(message.strip())
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def get_notices() -> tuple[str, ...]:
|
|
256
|
+
"""Devuelve una instantánea inmutable de los avisos actuales."""
|
|
257
|
+
with NOTICES_LOCK:
|
|
258
|
+
return tuple(NOTICES)
|
|
259
|
+
|
|
260
|
+
|
|
285
261
|
def get_daily_token() -> str:
|
|
286
262
|
"""Devuelve un token de sesión diario persistido en ~/zerochat/config/token.json."""
|
|
287
263
|
config_dir = get_data_dir() / "config"
|
|
@@ -310,6 +286,16 @@ SESSION_TOKEN = get_daily_token()
|
|
|
310
286
|
ACTIVE_PORT = DEFAULT_PORT
|
|
311
287
|
ACTIVE_HOST = DEFAULT_HOST
|
|
312
288
|
|
|
289
|
+
# Kept only for this Python process: binds an approved browser tool call to
|
|
290
|
+
# the exact JSON-RPC bytes sent to the local host.
|
|
291
|
+
TOOL_AUTH_VERSION = "zerochat-tool-auth-v1"
|
|
292
|
+
TOOL_AUTH_TTL_MS = 30_000
|
|
293
|
+
TOOL_AUTH_MAX_NONCES = 10_000
|
|
294
|
+
TOOL_AUTH_KEY = secrets.token_bytes(32)
|
|
295
|
+
TOOL_AUTH_SESSION_ID = secrets.token_urlsafe(18)
|
|
296
|
+
TOOL_AUTH_NONCES: dict[str, int] = {}
|
|
297
|
+
TOOL_AUTH_NONCES_LOCK = threading.Lock()
|
|
298
|
+
|
|
313
299
|
DETECTED_OS = "windows" if sys.platform.startswith("win") else ("android" if "ANDROID_ROOT" in os.environ else "linux")
|
|
314
300
|
|
|
315
301
|
|
|
@@ -381,16 +367,15 @@ def check_version():
|
|
|
381
367
|
installed = is_installed_runtime()
|
|
382
368
|
remote_ver = _read_remote_version(PYPI_VERSION_URL if installed else REMOTE_VERSION_URL)
|
|
383
369
|
if remote_ver and re.match(r"^\d+(\.\d+)+", remote_ver) and has_new_backend_version(remote_ver):
|
|
384
|
-
|
|
370
|
+
notice = f"Nueva versión del servidor disponible (local: {VERSION}, remota: {compatibility_version(remote_ver)})."
|
|
385
371
|
if installed:
|
|
386
|
-
|
|
372
|
+
notice += f" Actualiza cuando quieras con: {sys.executable} -m pip install --upgrade --no-cache-dir zerochat"
|
|
387
373
|
else:
|
|
388
|
-
|
|
374
|
+
notice += f" Actualiza con: curl -sSL {REMOTE_SCRIPT_URL} -o zerochat.py"
|
|
375
|
+
add_notice(notice)
|
|
389
376
|
except Exception:
|
|
390
377
|
# Modo offline o timeout ignorado de forma segura
|
|
391
378
|
pass
|
|
392
|
-
|
|
393
|
-
|
|
394
379
|
# ==============================================================================
|
|
395
380
|
# Herramientas Locales Core
|
|
396
381
|
# ==============================================================================
|
|
@@ -1163,6 +1148,38 @@ try {
|
|
|
1163
1148
|
_BROWSER_SESSION = PersistentBrowserSession()
|
|
1164
1149
|
|
|
1165
1150
|
|
|
1151
|
+
def browser_action_availability() -> dict:
|
|
1152
|
+
"""Comprueba requisitos locales sin lanzar Node.js ni Chromium."""
|
|
1153
|
+
if not shutil.which("node"):
|
|
1154
|
+
return {"available": False, "error": "Node.js is not installed or not found in system PATH."}
|
|
1155
|
+
playwright_locations = (
|
|
1156
|
+
Path.cwd() / "node_modules" / "playwright",
|
|
1157
|
+
get_data_dir() / "services" / "playwright" / "node_modules" / "playwright"
|
|
1158
|
+
)
|
|
1159
|
+
if not any(location.is_dir() for location in playwright_locations):
|
|
1160
|
+
return {"available": False, "error": "Playwright is not available."}
|
|
1161
|
+
browser_commands = (
|
|
1162
|
+
"google-chrome", "google-chrome-stable", "chromium", "chromium-browser",
|
|
1163
|
+
"msedge", "msedge.exe", "chrome", "chrome.exe"
|
|
1164
|
+
)
|
|
1165
|
+
if sys.platform == "darwin":
|
|
1166
|
+
playwright_cache = Path.home() / "Library" / "Caches" / "ms-playwright"
|
|
1167
|
+
elif sys.platform.startswith("win"):
|
|
1168
|
+
playwright_cache = Path(os.environ.get("LOCALAPPDATA", Path.home() / "AppData" / "Local")) / "ms-playwright"
|
|
1169
|
+
else:
|
|
1170
|
+
playwright_cache = Path.home() / ".cache" / "ms-playwright"
|
|
1171
|
+
try:
|
|
1172
|
+
has_playwright_browser = playwright_cache.is_dir() and any(
|
|
1173
|
+
child.is_dir() and child.name.startswith("chromium")
|
|
1174
|
+
for child in playwright_cache.iterdir()
|
|
1175
|
+
)
|
|
1176
|
+
except OSError:
|
|
1177
|
+
has_playwright_browser = False
|
|
1178
|
+
if has_playwright_browser or any(shutil.which(command) for command in browser_commands):
|
|
1179
|
+
return {"available": True}
|
|
1180
|
+
return {"available": False, "error": "Playwright Chromium is not installed."}
|
|
1181
|
+
|
|
1182
|
+
|
|
1166
1183
|
def browser_action(action: str, url: str | None = None, selector: str | None = None, value: str | None = None) -> str:
|
|
1167
1184
|
"""Control a headless browser for UI testing and visual inspection."""
|
|
1168
1185
|
try:
|
|
@@ -1321,7 +1338,6 @@ LOCAL_TOOL_HANDLERS = {
|
|
|
1321
1338
|
"get_diagnostics": get_diagnostics,
|
|
1322
1339
|
"browser_action": browser_action
|
|
1323
1340
|
}
|
|
1324
|
-
|
|
1325
1341
|
# ==============================================================================
|
|
1326
1342
|
# Servidor HTTP JSON-RPC 2.0 y SSE con Autenticación por Token
|
|
1327
1343
|
# ==============================================================================
|
|
@@ -2202,7 +2218,7 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2202
2218
|
return
|
|
2203
2219
|
self.send_header("Access-Control-Allow-Origin", origin if origin else "*")
|
|
2204
2220
|
self.send_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
|
2205
|
-
self.send_header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, X-ZeroChat-Token, X-ZeroChat-Client")
|
|
2221
|
+
self.send_header("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, X-ZeroChat-Token, X-ZeroChat-Client, X-ZeroChat-Tool-Session, X-ZeroChat-Tool-Expires, X-ZeroChat-Tool-Nonce, X-ZeroChat-Tool-Signature")
|
|
2206
2222
|
self.send_header("Access-Control-Allow-Private-Network", "true")
|
|
2207
2223
|
|
|
2208
2224
|
def verify_token(self) -> bool:
|
|
@@ -2221,6 +2237,42 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2221
2237
|
mark_browser_active()
|
|
2222
2238
|
return is_valid
|
|
2223
2239
|
|
|
2240
|
+
def verify_tool_authorization(self, body: bytes, request_path: str) -> str | None:
|
|
2241
|
+
"""Validate and atomically consume an authorization for one tool call."""
|
|
2242
|
+
session_id = self.headers.get("X-ZeroChat-Tool-Session", "")
|
|
2243
|
+
expires_raw = self.headers.get("X-ZeroChat-Tool-Expires", "")
|
|
2244
|
+
nonce = self.headers.get("X-ZeroChat-Tool-Nonce", "")
|
|
2245
|
+
signature = self.headers.get("X-ZeroChat-Tool-Signature", "")
|
|
2246
|
+
if (not isinstance(session_id, str) or len(session_id) > 128 or
|
|
2247
|
+
not isinstance(nonce, str) or not re.fullmatch(r"[A-Za-z0-9_-]{22,128}", nonce) or
|
|
2248
|
+
not isinstance(signature, str) or not re.fullmatch(r"[A-Za-z0-9_-]{43,128}", signature)):
|
|
2249
|
+
return "Missing or invalid tool authorization"
|
|
2250
|
+
try:
|
|
2251
|
+
expires_at = int(expires_raw)
|
|
2252
|
+
except (TypeError, ValueError):
|
|
2253
|
+
return "Missing or invalid tool authorization"
|
|
2254
|
+
now_ms = int(time.time() * 1000)
|
|
2255
|
+
if session_id != TOOL_AUTH_SESSION_ID or expires_at < now_ms or expires_at > now_ms + TOOL_AUTH_TTL_MS:
|
|
2256
|
+
return "Expired or invalid tool authorization"
|
|
2257
|
+
body_hash = hashlib.sha256(body).hexdigest()
|
|
2258
|
+
signature_base = json.dumps(
|
|
2259
|
+
[TOOL_AUTH_VERSION, session_id, "POST", request_path or "/", expires_at, nonce, body_hash],
|
|
2260
|
+
separators=(",", ":"), ensure_ascii=True
|
|
2261
|
+
).encode("utf-8")
|
|
2262
|
+
expected = base64.urlsafe_b64encode(hmac.new(TOOL_AUTH_KEY, signature_base, hashlib.sha256).digest()).rstrip(b"=").decode("ascii")
|
|
2263
|
+
if not hmac.compare_digest(signature, expected):
|
|
2264
|
+
return "Invalid tool authorization signature"
|
|
2265
|
+
with TOOL_AUTH_NONCES_LOCK:
|
|
2266
|
+
for value, expiry in list(TOOL_AUTH_NONCES.items()):
|
|
2267
|
+
if expiry < now_ms:
|
|
2268
|
+
del TOOL_AUTH_NONCES[value]
|
|
2269
|
+
if nonce in TOOL_AUTH_NONCES:
|
|
2270
|
+
return "Tool authorization was already used"
|
|
2271
|
+
if len(TOOL_AUTH_NONCES) >= TOOL_AUTH_MAX_NONCES:
|
|
2272
|
+
return "Tool authorization cache is full"
|
|
2273
|
+
TOOL_AUTH_NONCES[nonce] = expires_at
|
|
2274
|
+
return None
|
|
2275
|
+
|
|
2224
2276
|
def do_OPTIONS(self):
|
|
2225
2277
|
t0 = time.monotonic()
|
|
2226
2278
|
safe_path = sanitize_log_path(self.path)
|
|
@@ -2270,6 +2322,13 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2270
2322
|
self._log_res(200, safe_path, (time.monotonic() - t0) * 1000)
|
|
2271
2323
|
return
|
|
2272
2324
|
|
|
2325
|
+
# Browsers request this optional public resource without API credentials.
|
|
2326
|
+
if path_clean == "/favicon.ico":
|
|
2327
|
+
self.send_response(204)
|
|
2328
|
+
self.send_header("Content-Length", "0")
|
|
2329
|
+
self.end_headers()
|
|
2330
|
+
return
|
|
2331
|
+
|
|
2273
2332
|
if not is_heartbeat:
|
|
2274
2333
|
self._log_req("GET", safe_path)
|
|
2275
2334
|
|
|
@@ -2303,12 +2362,13 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2303
2362
|
self._log_res(200, f"{safe_path} [SSE canal activo]", (time.monotonic() - t0) * 1000)
|
|
2304
2363
|
return
|
|
2305
2364
|
|
|
2306
|
-
# Status general
|
|
2307
2365
|
res_data = json.dumps({
|
|
2308
2366
|
"status": "active",
|
|
2309
2367
|
"server": "ZeroChat Local Server",
|
|
2310
2368
|
"version": VERSION,
|
|
2369
|
+
"cwd": str(Path.cwd().resolve()),
|
|
2311
2370
|
"tools_count": len(LOCAL_TOOLS_DEFINITIONS),
|
|
2371
|
+
"browser_action": browser_action_availability(),
|
|
2312
2372
|
"os": DETECTED_OS
|
|
2313
2373
|
}, ensure_ascii=False, indent=2).encode("utf-8")
|
|
2314
2374
|
|
|
@@ -2431,6 +2491,11 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2431
2491
|
self._send_json_response(400, {"error": tool_args_error})
|
|
2432
2492
|
self._log_res(400, safe_path, (time.monotonic() - t0) * 1000, tool_args_error)
|
|
2433
2493
|
return
|
|
2494
|
+
auth_error = self.verify_tool_authorization(post_data, self.path.split("?", 1)[0].rstrip("/") or "/")
|
|
2495
|
+
if auth_error:
|
|
2496
|
+
self._send_json_response(403, {"error": auth_error})
|
|
2497
|
+
self._log_res(403, safe_path, (time.monotonic() - t0) * 1000, auth_error)
|
|
2498
|
+
return
|
|
2434
2499
|
|
|
2435
2500
|
req_path = self.path.split("?", 1)[0].rstrip("/")
|
|
2436
2501
|
|
|
@@ -2469,6 +2534,12 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2469
2534
|
},
|
|
2470
2535
|
"capabilities": {
|
|
2471
2536
|
"tools": {"listChanged": True}
|
|
2537
|
+
},
|
|
2538
|
+
"toolAuthorization": {
|
|
2539
|
+
"version": TOOL_AUTH_VERSION,
|
|
2540
|
+
"sessionId": TOOL_AUTH_SESSION_ID,
|
|
2541
|
+
"key": base64.urlsafe_b64encode(TOOL_AUTH_KEY).rstrip(b"=").decode("ascii"),
|
|
2542
|
+
"ttlMs": TOOL_AUTH_TTL_MS
|
|
2472
2543
|
}
|
|
2473
2544
|
}
|
|
2474
2545
|
elif method == "tools/list":
|
|
@@ -2498,14 +2569,34 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2498
2569
|
"protocolVersion": "2024-11-05",
|
|
2499
2570
|
"serverInfo": {
|
|
2500
2571
|
"name": "ZeroChat Local Server",
|
|
2501
|
-
"version": VERSION
|
|
2572
|
+
"version": VERSION,
|
|
2573
|
+
"cwd": str(Path.cwd().resolve())
|
|
2502
2574
|
},
|
|
2503
2575
|
"capabilities": {
|
|
2504
2576
|
"tools": {"listChanged": True}
|
|
2577
|
+
},
|
|
2578
|
+
"toolAuthorization": {
|
|
2579
|
+
"version": TOOL_AUTH_VERSION,
|
|
2580
|
+
"sessionId": TOOL_AUTH_SESSION_ID,
|
|
2581
|
+
"key": base64.urlsafe_b64encode(TOOL_AUTH_KEY).rstrip(b"=").decode("ascii"),
|
|
2582
|
+
"ttlMs": TOOL_AUTH_TTL_MS
|
|
2505
2583
|
}
|
|
2506
2584
|
}
|
|
2507
2585
|
elif method == "tools/list":
|
|
2508
|
-
|
|
2586
|
+
browser_availability = browser_action_availability()
|
|
2587
|
+
tools = []
|
|
2588
|
+
for definition in LOCAL_TOOLS_DEFINITIONS:
|
|
2589
|
+
item = dict(definition)
|
|
2590
|
+
if item.get("name") == "browser_action":
|
|
2591
|
+
item["availability"] = browser_availability
|
|
2592
|
+
tools.append(item)
|
|
2593
|
+
result = {"tools": tools}
|
|
2594
|
+
elif method == "tools/availability":
|
|
2595
|
+
requested_name = params.get("name", "") if isinstance(params, dict) else ""
|
|
2596
|
+
if requested_name != "browser_action":
|
|
2597
|
+
error = {"code": -32602, "message": "Herramienta no compatible con comprobación de disponibilidad."}
|
|
2598
|
+
else:
|
|
2599
|
+
result = browser_action_availability()
|
|
2509
2600
|
elif method == "tools/call":
|
|
2510
2601
|
tool_name = params.get("name", "") if isinstance(params, dict) else ""
|
|
2511
2602
|
tool_args = params.get("arguments", {}) if isinstance(params, dict) else {}
|
|
@@ -2595,7 +2686,6 @@ class ZeroChatServerHandler(BaseHTTPRequestHandler):
|
|
|
2595
2686
|
def log_message(self, format, *args):
|
|
2596
2687
|
# Silenciar logs ruidosos por defecto
|
|
2597
2688
|
pass
|
|
2598
|
-
|
|
2599
2689
|
def is_termux_environment() -> bool:
|
|
2600
2690
|
"""Devuelve si el proceso se ejecuta dentro de la instalación de Termux."""
|
|
2601
2691
|
termux_prefix = "/data/data/com.termux/files/usr"
|
|
@@ -2752,6 +2842,7 @@ def launch_browser(url: str) -> bool:
|
|
|
2752
2842
|
|
|
2753
2843
|
def main():
|
|
2754
2844
|
global ACTIVE_PORT, ACTIVE_HOST, SESSION_TOKEN, CONSOLE_CONTROL
|
|
2845
|
+
global TOOL_AUTH_KEY, TOOL_AUTH_SESSION_ID, TOOL_AUTH_NONCES
|
|
2755
2846
|
|
|
2756
2847
|
parser = argparse.ArgumentParser(description=f"ZeroChat Local Server v{VERSION}")
|
|
2757
2848
|
parser.add_argument("--port", type=int, default=int(os.environ.get("ZEROCHAT_PORT", DEFAULT_PORT)), help=f"Puerto de escucha (default: {DEFAULT_PORT})")
|
|
@@ -2765,6 +2856,9 @@ def main():
|
|
|
2765
2856
|
parser.add_argument("--version", action="version", version=f"ZeroChat {VERSION}")
|
|
2766
2857
|
args = parser.parse_args()
|
|
2767
2858
|
|
|
2859
|
+
# Los avisos no persisten entre ejecuciones del servidor.
|
|
2860
|
+
reset_notices()
|
|
2861
|
+
|
|
2768
2862
|
if args.test:
|
|
2769
2863
|
print(f"[{time.strftime('%H:%M:%S')}] TEST list_directory {'ok' if json.loads(list_directory('.'))['success'] else 'error'}")
|
|
2770
2864
|
print(f"[{time.strftime('%H:%M:%S')}] TEST read_file {'ok' if json.loads(read_file('package.json', max_lines=5))['success'] else 'error'}")
|
|
@@ -2776,6 +2870,14 @@ def main():
|
|
|
2776
2870
|
if not args.no_venv:
|
|
2777
2871
|
ensure_virtual_environment()
|
|
2778
2872
|
|
|
2873
|
+
browser_availability = browser_action_availability()
|
|
2874
|
+
if not browser_availability.get("available"):
|
|
2875
|
+
add_notice(
|
|
2876
|
+
"browser_action no está disponible y permanecerá desactivada. "
|
|
2877
|
+
"Instala Node.js, Playwright y Chromium: "
|
|
2878
|
+
"https://albalday.github.io/zerochat/help/browser-action.html"
|
|
2879
|
+
)
|
|
2880
|
+
|
|
2779
2881
|
# 2. Detectar entorno de desarrollo y resolver URL de destino
|
|
2780
2882
|
dev_root = get_dev_root()
|
|
2781
2883
|
static_root = get_static_root()
|
|
@@ -2792,6 +2894,11 @@ def main():
|
|
|
2792
2894
|
SESSION_TOKEN = args.token
|
|
2793
2895
|
else:
|
|
2794
2896
|
SESSION_TOKEN = get_daily_token()
|
|
2897
|
+
# A restart deliberately invalidates every browser-side signing credential.
|
|
2898
|
+
TOOL_AUTH_KEY = secrets.token_bytes(32)
|
|
2899
|
+
TOOL_AUTH_SESSION_ID = secrets.token_urlsafe(18)
|
|
2900
|
+
with TOOL_AUTH_NONCES_LOCK:
|
|
2901
|
+
TOOL_AUTH_NONCES = {}
|
|
2795
2902
|
|
|
2796
2903
|
server = ThreadingHTTPServer((ACTIVE_HOST, ACTIVE_PORT), ZeroChatServerHandler)
|
|
2797
2904
|
|
zerochat-7.11.0/PKG-INFO
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: zerochat
|
|
3
|
-
Version: 7.11.0
|
|
4
|
-
Summary: Private local web client for AI models, tools and MCP services
|
|
5
|
-
Author: Alberto Alday
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://albalday.github.io/zerochat/
|
|
8
|
-
Project-URL: Repository, https://github.com/albalday/zerochat
|
|
9
|
-
Project-URL: Issues, https://github.com/albalday/zerochat/issues
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Environment :: Web Environment
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
Requires-Python: >=3.10
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
License-File: LICENSE
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
|
|
23
|
-
# ZeroChat
|
|
24
|
-
|
|
25
|
-
ZeroChat es un cliente web universal para interactuar con modelos de inteligencia artificial y agentes de forma privada, rápida y sin intermediarios.
|
|
26
|
-
|
|
27
|
-
Funciona de forma estática en el navegador (servido por GitHub Pages o directamente desde local en un único archivo HTML), almacenando tus conversaciones, configuraciones y datos de forma segura en tu propio dispositivo (IndexedDB).
|
|
28
|
-
|
|
29
|
-
## Características principales
|
|
30
|
-
|
|
31
|
-
- **Multi-proveedor y modelos locales**: compatible con APIs estándar (OpenAI, Anthropic Claude, Google Gemini, OpenRouter) y motores locales (Ollama, LM Studio, vLLM, WebLLM con WebGPU directo en el navegador).
|
|
32
|
-
- **Herramientas y MCP (Model Context Protocol)**: soporte para agentes, herramientas de búsqueda/cálculo y servidores MCP locales coordinados mediante `zerochat.py`.
|
|
33
|
-
- **Conocimiento local (RAG)**: carga de documentos y recuperación contextual procesada íntegramente en el navegador.
|
|
34
|
-
- **Privacidad absoluta**: tus claves API y datos viajan directamente de tu navegador al proveedor seleccionado, sin servidores puente de terceros.
|
|
35
|
-
- **Sin necesidad de empaquetado**: distribuible de forma universal y ligera.
|
|
36
|
-
|
|
37
|
-
## Inicio rápido
|
|
38
|
-
|
|
39
|
-
- **Uso web directo**: abre [zerochat.html en GitHub Pages](https://albalday.github.io/zerochat/zerochat.html).
|
|
40
|
-
- **Servidor local con herramientas MCP**:
|
|
41
|
-
```bash
|
|
42
|
-
python3 zerochat.py
|
|
43
|
-
```
|
|
44
|
-
Inicia el asistente local, crea `~/zerochat/.venv` para los MCP y abre la interfaz web en tu navegador.
|
|
45
|
-
- **Instalación con PyPI**:
|
|
46
|
-
```bash
|
|
47
|
-
pip install zerochat
|
|
48
|
-
zerochat
|
|
49
|
-
```
|
|
50
|
-
Es la vía recomendada para instalar el servidor local desde PyPI. Igual que con la descarga directa, crea `~/zerochat/` para el estado y los MCP; la interfaz se carga desde GitHub Pages.
|
|
51
|
-
|
|
52
|
-
En ambos modos, `~/zerochat/` contiene configuración, token, servicios MCP y sus dependencias Python en `.venv/`. Borrar ese directorio elimina el estado local y los MCP, sin desinstalar el ejecutable de PyPI ni el archivo descargado.
|
|
53
|
-
|
|
54
|
-
Las publicaciones se realizan desde el repositorio oficial mediante GitHub Actions y PyPI Trusted Publishing.
|
|
55
|
-
|
|
56
|
-
## Documentación y Ayuda
|
|
57
|
-
|
|
58
|
-
Para consultar guías paso a paso, configuración de modelos, perfiles y agentes:
|
|
59
|
-
|
|
60
|
-
- 📖 **[Centro de Ayuda de ZeroChat (Español)](https://albalday.github.io/zerochat/help/index.html)**
|
|
61
|
-
- 📖 **[ZeroChat Documentation & Help (English)](https://albalday.github.io/zerochat/help/en/index.html)**
|
|
62
|
-
|
|
63
|
-
## Desarrollo
|
|
64
|
-
|
|
65
|
-
Para ejecutar las pruebas del proyecto:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
npm install
|
|
69
|
-
npm test
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Consulta [`AGENTS.md`](./AGENTS.md) para conocer las normas de desarrollo y arquitectura, y [`tests/README.md`](./tests/README.md) para la suite de pruebas.
|
zerochat-7.11.0/README.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# ZeroChat
|
|
2
|
-
|
|
3
|
-
ZeroChat es un cliente web universal para interactuar con modelos de inteligencia artificial y agentes de forma privada, rápida y sin intermediarios.
|
|
4
|
-
|
|
5
|
-
Funciona de forma estática en el navegador (servido por GitHub Pages o directamente desde local en un único archivo HTML), almacenando tus conversaciones, configuraciones y datos de forma segura en tu propio dispositivo (IndexedDB).
|
|
6
|
-
|
|
7
|
-
## Características principales
|
|
8
|
-
|
|
9
|
-
- **Multi-proveedor y modelos locales**: compatible con APIs estándar (OpenAI, Anthropic Claude, Google Gemini, OpenRouter) y motores locales (Ollama, LM Studio, vLLM, WebLLM con WebGPU directo en el navegador).
|
|
10
|
-
- **Herramientas y MCP (Model Context Protocol)**: soporte para agentes, herramientas de búsqueda/cálculo y servidores MCP locales coordinados mediante `zerochat.py`.
|
|
11
|
-
- **Conocimiento local (RAG)**: carga de documentos y recuperación contextual procesada íntegramente en el navegador.
|
|
12
|
-
- **Privacidad absoluta**: tus claves API y datos viajan directamente de tu navegador al proveedor seleccionado, sin servidores puente de terceros.
|
|
13
|
-
- **Sin necesidad de empaquetado**: distribuible de forma universal y ligera.
|
|
14
|
-
|
|
15
|
-
## Inicio rápido
|
|
16
|
-
|
|
17
|
-
- **Uso web directo**: abre [zerochat.html en GitHub Pages](https://albalday.github.io/zerochat/zerochat.html).
|
|
18
|
-
- **Servidor local con herramientas MCP**:
|
|
19
|
-
```bash
|
|
20
|
-
python3 zerochat.py
|
|
21
|
-
```
|
|
22
|
-
Inicia el asistente local, crea `~/zerochat/.venv` para los MCP y abre la interfaz web en tu navegador.
|
|
23
|
-
- **Instalación con PyPI**:
|
|
24
|
-
```bash
|
|
25
|
-
pip install zerochat
|
|
26
|
-
zerochat
|
|
27
|
-
```
|
|
28
|
-
Es la vía recomendada para instalar el servidor local desde PyPI. Igual que con la descarga directa, crea `~/zerochat/` para el estado y los MCP; la interfaz se carga desde GitHub Pages.
|
|
29
|
-
|
|
30
|
-
En ambos modos, `~/zerochat/` contiene configuración, token, servicios MCP y sus dependencias Python en `.venv/`. Borrar ese directorio elimina el estado local y los MCP, sin desinstalar el ejecutable de PyPI ni el archivo descargado.
|
|
31
|
-
|
|
32
|
-
Las publicaciones se realizan desde el repositorio oficial mediante GitHub Actions y PyPI Trusted Publishing.
|
|
33
|
-
|
|
34
|
-
## Documentación y Ayuda
|
|
35
|
-
|
|
36
|
-
Para consultar guías paso a paso, configuración de modelos, perfiles y agentes:
|
|
37
|
-
|
|
38
|
-
- 📖 **[Centro de Ayuda de ZeroChat (Español)](https://albalday.github.io/zerochat/help/index.html)**
|
|
39
|
-
- 📖 **[ZeroChat Documentation & Help (English)](https://albalday.github.io/zerochat/help/en/index.html)**
|
|
40
|
-
|
|
41
|
-
## Desarrollo
|
|
42
|
-
|
|
43
|
-
Para ejecutar las pruebas del proyecto:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
npm install
|
|
47
|
-
npm test
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Consulta [`AGENTS.md`](./AGENTS.md) para conocer las normas de desarrollo y arquitectura, y [`tests/README.md`](./tests/README.md) para la suite de pruebas.
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: zerochat
|
|
3
|
-
Version: 7.11.0
|
|
4
|
-
Summary: Private local web client for AI models, tools and MCP services
|
|
5
|
-
Author: Alberto Alday
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Project-URL: Homepage, https://albalday.github.io/zerochat/
|
|
8
|
-
Project-URL: Repository, https://github.com/albalday/zerochat
|
|
9
|
-
Project-URL: Issues, https://github.com/albalday/zerochat/issues
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: Environment :: Web Environment
|
|
12
|
-
Classifier: Operating System :: OS Independent
|
|
13
|
-
Classifier: Programming Language :: Python :: 3
|
|
14
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
-
Requires-Python: >=3.10
|
|
19
|
-
Description-Content-Type: text/markdown
|
|
20
|
-
License-File: LICENSE
|
|
21
|
-
Dynamic: license-file
|
|
22
|
-
|
|
23
|
-
# ZeroChat
|
|
24
|
-
|
|
25
|
-
ZeroChat es un cliente web universal para interactuar con modelos de inteligencia artificial y agentes de forma privada, rápida y sin intermediarios.
|
|
26
|
-
|
|
27
|
-
Funciona de forma estática en el navegador (servido por GitHub Pages o directamente desde local en un único archivo HTML), almacenando tus conversaciones, configuraciones y datos de forma segura en tu propio dispositivo (IndexedDB).
|
|
28
|
-
|
|
29
|
-
## Características principales
|
|
30
|
-
|
|
31
|
-
- **Multi-proveedor y modelos locales**: compatible con APIs estándar (OpenAI, Anthropic Claude, Google Gemini, OpenRouter) y motores locales (Ollama, LM Studio, vLLM, WebLLM con WebGPU directo en el navegador).
|
|
32
|
-
- **Herramientas y MCP (Model Context Protocol)**: soporte para agentes, herramientas de búsqueda/cálculo y servidores MCP locales coordinados mediante `zerochat.py`.
|
|
33
|
-
- **Conocimiento local (RAG)**: carga de documentos y recuperación contextual procesada íntegramente en el navegador.
|
|
34
|
-
- **Privacidad absoluta**: tus claves API y datos viajan directamente de tu navegador al proveedor seleccionado, sin servidores puente de terceros.
|
|
35
|
-
- **Sin necesidad de empaquetado**: distribuible de forma universal y ligera.
|
|
36
|
-
|
|
37
|
-
## Inicio rápido
|
|
38
|
-
|
|
39
|
-
- **Uso web directo**: abre [zerochat.html en GitHub Pages](https://albalday.github.io/zerochat/zerochat.html).
|
|
40
|
-
- **Servidor local con herramientas MCP**:
|
|
41
|
-
```bash
|
|
42
|
-
python3 zerochat.py
|
|
43
|
-
```
|
|
44
|
-
Inicia el asistente local, crea `~/zerochat/.venv` para los MCP y abre la interfaz web en tu navegador.
|
|
45
|
-
- **Instalación con PyPI**:
|
|
46
|
-
```bash
|
|
47
|
-
pip install zerochat
|
|
48
|
-
zerochat
|
|
49
|
-
```
|
|
50
|
-
Es la vía recomendada para instalar el servidor local desde PyPI. Igual que con la descarga directa, crea `~/zerochat/` para el estado y los MCP; la interfaz se carga desde GitHub Pages.
|
|
51
|
-
|
|
52
|
-
En ambos modos, `~/zerochat/` contiene configuración, token, servicios MCP y sus dependencias Python en `.venv/`. Borrar ese directorio elimina el estado local y los MCP, sin desinstalar el ejecutable de PyPI ni el archivo descargado.
|
|
53
|
-
|
|
54
|
-
Las publicaciones se realizan desde el repositorio oficial mediante GitHub Actions y PyPI Trusted Publishing.
|
|
55
|
-
|
|
56
|
-
## Documentación y Ayuda
|
|
57
|
-
|
|
58
|
-
Para consultar guías paso a paso, configuración de modelos, perfiles y agentes:
|
|
59
|
-
|
|
60
|
-
- 📖 **[Centro de Ayuda de ZeroChat (Español)](https://albalday.github.io/zerochat/help/index.html)**
|
|
61
|
-
- 📖 **[ZeroChat Documentation & Help (English)](https://albalday.github.io/zerochat/help/en/index.html)**
|
|
62
|
-
|
|
63
|
-
## Desarrollo
|
|
64
|
-
|
|
65
|
-
Para ejecutar las pruebas del proyecto:
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
npm install
|
|
69
|
-
npm test
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Consulta [`AGENTS.md`](./AGENTS.md) para conocer las normas de desarrollo y arquitectura, y [`tests/README.md`](./tests/README.md) para la suite de pruebas.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|